require 'fig/package'

module Fig

grammar Fig
  rule package
    ws statements:(package_statement*) {
      def to_package(package_name, version_name, directory)
        Package.new(package_name, version_name, directory, statements.elements.map { |statement| statement.to_package_statement })
      end
    }
  end

  rule package_statement
    archive / resource / retrieve / config
  end

  rule archive
    "archive" ws url {
      def to_package_statement
        Archive.new(url.value.text_value)
      end
    }
  end

  rule resource
    "resource" ws url {
      def to_package_statement
        Resource.new(url.value.text_value)
      end
    }
  end

  rule retrieve
    "retrieve" ws var:[@a-zA-Z0-9/\._]+ "->" path:[a-zA-Z0-9_/\.\-\[\]]+ ws {
      def to_package_statement
        Retrieve.new(var.text_value, path.text_value)
      end
    }
  end

  rule install
    "install" ws statements:config_statement* "end" ws {
      def to_package_statement
        Install.new(statements.elements.map { |statement| statement.to_config_statement })
      end
    }
  end

  rule config
    "config" ws config_name ws statements:config_statement* "end" ws {
      def to_package_statement
        Configuration.new(config_name.text_value, statements.elements.map { |statement| statement.to_config_statement })
      end
    }
  end

  rule config_statement
    include / command / path / set
  end

  rule include
    "include" ws descriptor overrides:(override*) {
      def to_config_statement
        package = descriptor.respond_to?(:package) ? descriptor.package.text_value : nil
        config = descriptor.get_config
        version = descriptor.get_version
        Include.new(package, config, version, overrides.elements.map{ |e| e.to_override })
      end
    }
  end

  rule override
    "override" ws package_name "/" version_name ws {
      def to_override
        return Override.new(package_name.text_value, version_name.text_value)
      end
    }
  end

  rule path
    ("append" / "path" / "add") ws name:[a-zA-Z0-9_]+ "=" value:[@a-zA-Z0-9/\-\\._]+ ws {
      def to_config_statement
        Path.new(name.text_value, value.text_value)
      end
    }
  end

  rule set
    "set" ws name:[a-zA-Z0-9_]+ "=" value:[@a-zA-Z0-9/\-\\._]+ ws {
      def to_config_statement
        Set.new(name.text_value, value.text_value)
      end
    }
  end

  rule command
    "command" ws string {
      def to_config_statement
        Command.new(string.value.text_value)
      end
    }
  end

  rule string
    '"' value:(!'"' . )* '"' ws
  end

  rule descriptor
    ((package:package_name ("/" version:version_name)? (":" config:config_name)? ws) /
    (":" config:config_name ws)) {
      def get_version
        elements.each do |element|
          if element.respond_to?(:version)
            return element.version.text_value
          end
        end
        nil
      end
      def get_config
        return self.config.text_value if self.respond_to?(:config)
        elements.each do |element|
          if element.respond_to?(:config)
            return element.config.text_value
          end
        end
        nil
      end
    }
  end

  rule package_name
    [a-zA-Z0-9.-]+
  end

  rule version_name
    [a-zA-Z0-9_\-.]+
  end

  rule config_name
    [a-zA-Z0-9_\-.]+
  end

  rule name
    value:[a-zA-Z0-9]+ ws
  end

  rule url
    (value:[a-zA-Z0-9:/\-\\._\*]+ ws) / ('"' value:[a-zA-Z0-9:/\-\\._]+ '"' ws)
  end

  rule ws
    [ \n\r\t]+
  end
end

end