text: #  Copyright 2008-2012 Nokia Siemens Networks Oyj
  #
  #  Licensed under the Apache License, Version 2.0 (the "License");
  #  you may not use this file except in compliance with the License.
  #  You may obtain a copy of the License at
  #
  #      http://www.apache.org/licenses/LICENSE-2.0
  #
  #  Unless required by applicable law or agreed to in writing, software
  #  distributed under the License is distributed on an "AS IS" BASIS,
  #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  #  See the License for the specific language governing permissions and
  #  limitations under the License.
  
  
  class VariableSplitter:
  
      def __init__(self, string, identifiers):
          self.identifier = None
          self.base = None
          self.index = None
          self.start = -1
          self.end = -1
          self._identifiers = identifiers
          self._may_have_internal_variables = False
          try:
              self._split(string)
          except ValueError:
              pass
          else:
              self._finalize()
  
      def get_replaced_base(self, variables):
          if self._may_have_internal_variables:
              return variables.replace_string(self.base)
          return self.base
  
      def _finalize(self):
          self.identifier = self._variable_chars[0]
          self.base = ''.join(self._variable_chars[2:-1])
          self.end = self.start + len(self._variable_chars)
          if self._has_list_variable_index():
              self.index = ''.join(self._list_variable_index_chars[1:-1])
              self.end += len(self._list_variable_index_chars)
  
      def _has_list_variable_index(self):
          return self._list_variable_index_chars \
              and self._list_variable_index_chars[-1] == ']'
  
      def _split(self, string):
          start_index, max_index = self._find_variable(string)
          self.start = start_index
          self._open_curly = 1
          self._state = self._variable_state
          self._variable_chars = [string[start_index], '{']
          self._list_variable_index_chars = []
          self._string = string
          start_index += 2
          for index, char in enumerate(string[start_index:]):
              index += start_index  # Giving start to enumerate only in Py 2.6+
              try:
                  self._state(char, index)
              except StopIteration:
                  return
              if index  == max_index and not self._scanning_list_variable_index():
                  return
  
      def _scanning_list_variable_index(self):
          return self._state in [self._waiting_list_variable_index_state,
                                 self._list_variable_index_state]
  
      def _find_variable(self, string):
          max_end_index = string.rfind('}')
          if max_end_index == -1:
              raise ValueError('No variable end found')
          if self._is_escaped(string, max_end_index):
              return self._find_variable(string[:max_end_index])
          start_index = self._find_start_index(string, 1, max_end_index)
          if start_index == -1:
              raise ValueError('No variable start found')
          return start_index, max_end_index
  
      def _find_start_index(self, string, start, end):
          index = string.find('{', start, end) - 1
          if index < 0:
              return -1
          if self._start_index_is_ok(string, index):
              return index
          return self._find_start_index(string, index+2, end)
  
      def _start_index_is_ok(self, string, index):
          return string[index] in self._identifiers \
              and not self._is_escaped(string, index)
  
      def _is_escaped(self, string, index):
          escaped = False
          while index > 0 and string[index-1] == '\\':
              index -= 1
              escaped = not escaped
          return escaped
  
      def _variable_state(self, char, index):
          self._variable_chars.append(char)
          if char == '}' and not self._is_escaped(self._string, index):
              self._open_curly -= 1
              if self._open_curly == 0:
                  if not self._is_list_variable():
                      raise StopIteration
                  self._state = self._waiting_list_variable_index_state
          elif char in self._identifiers:
              self._state = self._internal_variable_start_state
  
      def _is_list_variable(self):
          return self._variable_chars[0] == '@'
  
      def _internal_variable_start_state(self, char, index):
          self._state = self._variable_state
          if char == '{':
              self._variable_chars.append(char)
              self._open_curly += 1
              self._may_have_internal_variables = True
          else:
              self._variable_state(char, index)
  
      def _waiting_list_variable_index_state(self, char, index):
          if char != '[':
              raise StopIteration
          self._list_variable_index_chars.append(char)
          self._state = self._list_variable_index_state
  
      def _list_variable_index_state(self, char, index):
          self._list_variable_index_chars.append(char)
          if char == ']':
              raise StopIteration
  