module Wukong
  module FlatPack
    module Tokens
      TOKEN_CLASSES = {}
      
      def self.token_for_indicator(indicator)
        return TOKEN_CLASSES[indicator].new
      end
      
      class Token
        attr_accessor :position
        attr_accessor :length
        attr_accessor :indicator

        def self.indicator= indicator
          TOKEN_CLASSES[indicator] = self
          @indicator = indicator
        end
      end

      class FixedPointToken < Token
        attr_accessor :power
        attr_accessor :strict

        self.indicator = 'D'

        #TODO: Allow negative powers
        def re
          strict ? "(?:(?:\\+|-)\\d{#{@length-1}}|\\d{#{@length}})" : ".{#{@length}}"
        end
        
        def translate str
          return nil if str.strip == ""
          base = str.to_f
          return base / (10**@power)
        end
      end

      class BasicToken < Token
        attr_accessor :modifier
     
        def re token= '.'
          if not @length.nil?
            return "#{token}{#{@length}}"
          elsif not @modifier.nil?
            return "#{token}#{@modifier}"
          else
            return token
          end
        end

      end
      
      class IntToken < BasicToken
        self.indicator = 'i'
        RE = '(?:\+|-)?\\d'

        def re
          if not @length.nil?
            return "(?:(?:\\+|-)\\d{#{@length-1}}|\\d{#{@length}})"
          elsif not @modifier.nil?
            return "#{RE}#{@modifier}"
          else
            return RE
          end
        end

        def translate str
          return Integer(str)
        rescue ArgumentError => err
          return str.to_i
        end
      end

      class StringToken < BasicToken
        self.indicator = 's'
        
        def translate str
          return str
        end
      end

      class  FloatToken < BasicToken
        self.indicator = 'f'
        #TODO: Implement floats

        def get_re
          #TODO: Implement 
        end

        def translate
          #TODO: Implement
        end
      end
     
      class BoolToken < BasicToken
        self.indicator = 'b'
        TRUE_TOKENS = ['t','y','1'] 
        FALSE_TOKENS = ['f','n','0']
        
        #TODO: Add back multi-char options and think through allowing padding
        #TODO: Allow users to override true and false

        def re
          return "(?:#{(TRUE_TOKENS + TRUE_TOKENS.map {|c| c.upcase} +
                       FALSE_TOKENS + FALSE_TOKENS.map{|c| c.upcase}).join('|')})"
        end

        def translate str
          if TRUE_TOKENS.include?(str.downcase)
            return true
          elsif FALSE_TOKENS.include?(str.downcase)
            return false
          else
            return nil
          end
        end
      end

      class IgnoreToken < BasicToken
        self.indicator = '_'

        # ignore symbols are removed from the final output
        def translate str
          return :ignore
        end
      end
    end
  end
end