class AwsRecord::Generators::Base

def ensure_hkey

def ensure_hkey
  uuid_member = nil
  hkey_member = nil
  rkey_member = nil
  attributes.each do |attr|
    if attr.options.key? :hash_key
      if hkey_member
        @parse_errors << ArgumentError.new("Redefinition of hash_key attr: #{attr.name}, original declaration of hash_key on: #{hkey_member.name}")
        next
      end
      hkey_member = attr
    elsif attr.options.key? :range_key
      if rkey_member
        @parse_errors << ArgumentError.new("Redefinition of range_key attr: #{attr.name}, original declaration of range_key on: #{hkey_member.name}")
        next
      end
      rkey_member = attr
    end
    uuid_member = attr if attr.name.include? 'uuid'
  end
  return if hkey_member
  if uuid_member
    uuid_member.options[:hash_key] = true
  else
    attributes.unshift GeneratedAttribute.parse('uuid:hkey')
  end
end

def ensure_unique_fields

def ensure_unique_fields
  used_names = Set.new
  duplicate_fields = []
  attributes.each do |attr|
    duplicate_fields << [:attribute, attr.name] if used_names.include? attr.name
    used_names.add attr.name
    next unless attr.options.key? :database_attribute_name
    raw_db_attr_name = attr.options[:database_attribute_name].delete('"') # db attribute names are wrapped with " to make template generation easier
    duplicate_fields << [:database_attribute_name, raw_db_attr_name] if used_names.include? raw_db_attr_name
    used_names.add raw_db_attr_name
  end
  return if duplicate_fields.empty?
  duplicate_fields.each do |invalid_attr|
    @parse_errors << ArgumentError.new("Found duplicated field name: #{invalid_attr[1]}, in attribute#{invalid_attr[0]}")
  end
end

def has_validations?

def has_validations?
  !@required_attrs.empty? || !@length_validations.empty?
end

def initialize(args, *options)

def initialize(args, *options)
  options[0] << '--skip-table-config' if options[1][:behavior] == :revoke
  @parse_errors = []
  super
  ensure_unique_fields
  ensure_hkey
  parse_gsis!
  parse_table_config!
  parse_validations!
  return if @parse_errors.empty?
  warn 'The following errors were encountered while trying to parse the given attributes'
  $stderr.puts
  warn @parse_errors
  $stderr.puts
  abort('Please fix the errors before proceeding.')
end

def mutation_tracking_disabled?

def mutation_tracking_disabled?
  options['disable_mutation_tracking']
end

def parse_attributes!

def parse_attributes!
  self.attributes = (attributes || []).map do |attr|
    GeneratedAttribute.parse(attr)
  rescue ArgumentError => e
    @parse_errors << e
    next
  end
  self.attributes = attributes.compact
  if options['password_digest']
    attributes << GeneratedAttribute.new('password_digest', :string_attr, digest: true)
  end
  return unless options['timestamps']
  attributes << GeneratedAttribute.parse('created:datetime:default_value{Time.now}')
  attributes << GeneratedAttribute.parse('updated:datetime:default_value{Time.now}')
end

def parse_gsis!

def parse_gsis!
  @gsis = (options['gsi'] || []).map do |raw_idx|
    idx = SecondaryIndex.parse(raw_idx)
    attributes = self.attributes.select { |attr| attr.name == idx.hash_key }
    if attributes.empty?
      @parse_errors << ArgumentError.new("Could not find attribute #{idx.hash_key} for gsi #{idx.name} hkey")
      next
    end
    if idx.range_key
      attributes = self.attributes.select { |attr| attr.name == idx.range_key }
      if attributes.empty?
        @parse_errors << ArgumentError.new("Could not find attribute #{idx.range_key} for gsi #{idx.name} rkey")
        next
      end
    end
    idx
  rescue ArgumentError => e
    @parse_errors << e
    next
  end
  @gsis = @gsis.compact
end

def parse_rw_units(name)

def parse_rw_units(name)
  if options['table_config'].key? name
    rw_units = options['table_config'][name]
    rw_units.gsub(/[,.-]/, ':').split(':').reject(&:empty?)
  else
    @parse_errors << ArgumentError.new("Please provide a table_config definition for #{name}")
  end
end

def parse_table_config!

def parse_table_config!
  return unless options['table_config']
  @primary_read_units, @primary_write_units = parse_rw_units('primary')
  @gsi_rw_units = @gsis.to_h do |idx|
    [idx.name, parse_rw_units(idx.name)]
  end
  options['table_config'].each_key do |config|
    next if config == 'primary'
    gsi = @gsis.select { |idx| idx.name == config }
    @parse_errors << ArgumentError.new("Could not find a gsi declaration for #{config}") if gsi.empty?
  end
end

def parse_validations!

def parse_validations!
  @required_attrs = options['required'] ? options['required'].split(',') : []
  @required_attrs.each do |val_attr|
    @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if attributes.none? do |attr|
                                                                                                 attr.name == val_attr
                                                                                               end
  end
  @length_validations = options['length_validations'].map do |val_attr, bounds|
    @parse_errors << ArgumentError.new("No such field #{val_attr} in required validations") if attributes.none? do |attr|
                                                                                                 attr.name == val_attr
                                                                                               end
    bounds = bounds.gsub(/[,.-]/, ':').split(':').reject(&:empty?)
    [val_attr, "#{bounds[0]}..#{bounds[1]}"]
  end
  @length_validations = @length_validations.to_h
end