require File.dirname(__FILE__) + '/csv'
require File.dirname(__FILE__) + '/json'

class NilClass
	def xmlize
		""
	end
	
	def blank?
	  return true 
	end
end

class String
	def xmlize
	  # using dump to escape unprintable characters 
		self.gsub("&", "&amp;").gsub("<", "&lt;").gsub(">", "&gt;").gsub("\"", "&quot;").gsub("'", "&apos;").dump[1..-2].gsub('\n', "\n").gsub('\\\\', '\\')
	end
	
	def blank?
	  return "" == self
	end
end


class AGDataObject
  attr_accessor :uuid, :trashed, :folderPath, :createdAt, :updatedAt, :lastUsedAt, :useCount, :title, :typeName, :location, :locationKey
  attr_accessor :secureContents, :openContents
  
  def initialize
    super
    @typeName = "UKNOWN"
    @uuid = nil
    @secureContents = {}
    @openContents = {}
  end
  
  def title
    @title || ""
  end
  
  def title=(v)
    @title = v || ""
    if @title =~ %r{^(.+)\\(.+)$}
      @folderPath = $1
      @title = $2
    end
  end
  
  def locationKey
    @locationKey || ""
  end
  
  def locationKey=(v)
    @locationKey = v || ""
  end

  def location
    @location || ""
  end
  
  def location=(v)
    @location = v || ""
  end

  def notes=(value)
    @secureContents["notesPlain"] = value || ""
  end
  
  def notes
    @secureContents["notesPlain"] || ""
  end
  
  def secureContents
    @secureContents
  end

  def attr_hash
    h = {}
    h['uuid'] = @uuid if @uuid
    h['trashed'] = @trashed if @trashed
    h['folderPath'] = @folderPath if @folderPath
    h['createdAt'] = @createdAt if @createdAt
    h['updatedAt'] = @updatedAt if @updatedAt
    h['lastUsedAt'] = @lastUsedAt if @lastUsedAt
    h['useCount'] = @useCount if @useCount
    h['title'] = @title if @title
    h['typeName'] = @typeName
    h['location'] = @location if @location
    h['locationKey'] = @location if @locationKey
    h['secureContents'] = @secureContents if @secureContents
    h['openContents'] = @openContents if @openContents
    return h
  end

  def to_json(*a)
    self.attr_hash.to_json(*a) rescue nil
  end
  
end

class WebFormValue
  attr_accessor :name, :value, :type, :status
  attr_accessor :designation
  
  @type = "T"
  @status = "R"

  def name=(v)
    @name = v || ""
  end
  
  def value=(v)
    @value = v || ""
  end
  
  def to_json(*a)
    hash = 
    {
      'name'  =>  self.name,
      'type'  =>  self.type,
      'value' =>  self.value
    }
    
    hash['designation'] = self.designation if self.designation
    return hash.to_json(*a)
  end
end

class WebForm < AGDataObject

  def initialize
    super
    @typeName = "webforms.WebForm"
  end

  def fields
    self.secureContents['fields'] ||= []
    return self.secureContents['fields']
  end

  def name=(v)
    self.title = v
  end

  def domain
    self.locationKey
  end
  
  def domain=(v)
    self.locationKey = v
  end
  
  def url=(url_string)
    url_string ||= ""
    if url_string == ""
      url_string = ""
    end 
    
    if url_string =~ %r{://}
      self.location = url_string
    else
      self.location = "http://" + url_string
    end
    
    if @url =~ %r{://([^/?]+)}
      self.domain = $1
    end
    
    if self.domain =~ /\.([^.][^.][^.]+\.[^.]+)$/
      self.domain = $1
    elsif self.domain =~ /\.([^.]+\.[^.][^.]\.[^.]+)$/
      self.domain = $1
    end
  end
  
#   def to_s
#     <<-PLIST
#   <dict>
#     <key>Domain</key>
#     <string>#{self.domain.xmlize}</string>
#     <key>Label</key>
#     <string></string>
#     <key>Name</key>
#     <string>#{self.name.xmlize}</string>
#     <key>Notes</key>
#     <string>#{self.notes.xmlize}</string>
#     <key>Options</key>
#     <integer>0</integer>
#     <key>URL</key>
#     <string>#{self.url.xmlize}</string>
#     <key>Values</key>
#     <array>
# #{self.values * "\n"}
#     </array>
#   </dict>
# PLIST
#   end
  
  def add_username(username)
    username ||= ""
    if username == ""
      username = "none"
    end
    
    v = WebFormValue.new
    v.name = "Username"
    v.type = "T"
    v.status = "R"
    v.value = username
    v.designation = "username"
    self.fields << v
  end
  
  def add_password(password)
    password ||= ""
    
    v = WebFormValue.new
    v.name = "Password"
    v.type = "P"
    v.status = "R"
    v.value = password
    v.designation = "password"
    self.fields << v
  end
  
  def add_field(name, value, type="U")
    v = WebFormValue.new
    v.name = name
    v.type = type
    v.status = "R"
    v.value = value
    self.fields << v
  end

  def add_login(username, password)
    self.add_username(username)
    self.add_password(password)
  end
  
end

class SecureNote < AGDataObject

  def initialize
    super
    @typeName = "securenotes.SecureNote"
  end

  def name=(v)
    self.title = v || ""
  end
  
end

class AGIdentity < AGDataObject
  def initialize
    super
    @typeName = "identities.Identity"
  end  
end

class AGPassword < AGDataObject
  def initialize
    super
    @typeName = "passwords.Password"
  end  
end

class AGCreditCard < AGDataObject
  def initialize
    super
    @typeName = "wallet.financial.CreditCard"
  end  

  def cardholder
    secureContents["cardholder"]
  end
  
  def cardholder=(value)
    secureContents["cardholder"] = value || ""
  end
  
  def cardType
    secureContents["type"]
  end
  
#	{ "name":"type", "type":"menu", "menuitems":["visa", "mc", "amex", "diners", "discover", "jcb", "solo", "switch", "maestro", "visaelectron", "carteblanche"] },

  def cardType=(value)
    secureContents["type"] = value || ""
  end

  def ccnum
    secureContents["ccnum"]
  end
  
  def ccnum=(value)
    secureContents["ccnum"] = value || ""
  end
  
  def cvv=(value)
    secureContents["cvv"] = value || ""
  end
  
  def pin=(value)
    secureContents["pin"] = value || ""
  end
  
  def bank=(value)
    secureContents["bank"] = value || ""
  end
  
  def expiration_date=(date)
    require 'date'
    begin
      myDate = date.instance_of?(Date) ? date : Date.parse(date.to_s)
      secureContents['expiry_mm'], secureContents['expiry_yy'] = myDate.month(), myDate.year()
    rescue ArgumentError
    end
  end
  # { "name":"expiry", "type":"expiration" },
  # { "name":"validFrom", "type":"expiration" }
  
end

class AGLicense < AGDataObject

  def initialize
    super
    @typeName = "wallet.computer.License"
  end  


  def product_name=(value)
    secureContents["product_name"] = value || ""
  end

  def product_version=(value)
    secureContents["product_version"] = value || ""
  end

  def reg_name=(value)
    secureContents["reg_name"] = value || ""
  end

  def reg_code=(value)
    secureContents["reg_code"] = value || ""
  end

  def reg_email=(value)
    secureContents["reg_email"] = value || ""
  end

  def company=(value)
    secureContents["company"] = value || ""
  end
  
  def price=(value)
    secureContents["retail_price"] = value || ""
  end

  def publisher_name=(value)
    secureContents["publisher_name"] = value || ""
  end

  def support_email=(value)
    secureContents["support_email"] = value || ""
  end

  def download_link=(value)
    secureContents["download_link"] = value || ""
  end

  def publisher_website=(value)
    secureContents["publisher_website"] = value || ""
  end
  
  def order_date=(value)
    secureContents["order_date"] = value || ""
  end
  
  def order_number=(value)
    secureContents["order_number"] = value || ""
  end

  def order_total=(value)
    secureContents["order_total"] = value || ""
  end

end

class AGFTPAccount < AGDataObject
  
  def initialize
    super
    @typeName = "wallet.onlineservices.FTP"
  end  

  def server
    secureContents["server"]
  end

  def server=(value)
    secureContents["server"] = value || ""
  end

  def path
    secureContents["path"]
  end
  
  def path=(value)
    secureContents["path"] = value || ""
  end
  
  def add_login(username, password)
    self.username = username
    self.password = password
  end
  
  def username=(value)
    secureContents["username"] = value || ""
  end
  
  def password=(value)
    secureContents["password"] = value || ""
  end
  
    # { "name":"provider", "type":"string" },
    # { "name":"provider_website", "type":"string" },
    # { "name":"phone_local", "type":"string" },
    # { "name":"phone_tollfree", "type":"string" }
  
end


class AGBankAccountUS < AGDataObject
  
  def initialize
    super
    @typeName = "wallet.financial.BankAccountUS"
  end  

  def bankName
    secureContents["bankName"]
  end
  
  def bankName=(value)
    secureContents["bankName"] = value || ""
  end
  
  def owner 
    secureContents["owner"]
  end
  
  def owner=(value)
    secureContents["owner"] = value || ""
  end
  
  #	{ "name":"accountType", "type":"menu", "menuitems":["checking", "savings", "loc", "money_market", "other"] },

  def routingNo
    secureContents["routingNo"]
  end
  
  def routingNo=(value)
    secureContents["routingNo"] = value || ""
  end

  def accountNo
    secureContents["accountNo"]
  end
  
  def accountNo=(value)
    secureContents["accountNo"] = value || ""
  end

  def branchPhone=(value)
    secureContents["branchPhone"] = value || ""
  end
  # { "name":"swift", "type":"string" },
  # { "name":"iban", "type":"string" }
  
end

class Importer
  
  def initialize
    super
    @items = []
    @errors = []
  end

  def run
    process_stdin
  end

  def add_item(item)
    @items << item
  end
  
  def add_error(e)
    @errors << e
  end

  def process_contents(contents)
    lines = contents.gsub("\n\r", "\n").gsub("\r\n", "\n").gsub("\r", "\n").split("\n")
    process(lines)
  end

  def read_contents
    contents = $stdin.read
    
    # Convert UTF-16 to UTF-8
    if contents[0] == 255
      begin
        require 'iconv'
        converter = Iconv.new("UTF-8", "UTF-16")
        contents = converter.iconv(contents)
      rescue Exception
        # Iconv is a standard library but sometimes it is missing (?!). Ignore and let Cocoa try.
      end
    end
    
    return contents
  end

  def process_stdin
    contents = read_contents
    process_contents(contents) if contents && contents.length > 10
    
   jsons = @items.collect { |item| item.to_json }
   jsons = jsons.delete_if { |item| item == nil }
   puts jsons * "\n***5642bee8-a5ff-11dc-8314-0800200c9a66***\n"
  end

  # ------------------------------------------

  def process(lines)
    lines.each { |line| process_line(line) }
  end

  def process_line(line)
    # to be implemented in subclass
  end
  
  def description
    return "Must be implemented in subclass"
  end

end

