#   Copyright (c) 2010, Diaspora Inc.  This file is
#   licensed under the Affero General Public License version 3 or later.  See
#   the COPYRIGHT file.

require File.join(Rails.root, 'lib/hcard')

class Person
  include MongoMapper::Document
  include ROXML
  include Encryptor::Public
  require File.join(Rails.root, 'lib/diaspora/websocket')
  include Diaspora::Socketable

  xml_accessor :_id
  xml_accessor :diaspora_handle
  xml_accessor :url
  xml_accessor :profile, :as => Profile
  xml_reader :exported_key

  key :url, String
  key :diaspora_handle, String, :unique => true
  key :serialized_public_key, String

  key :owner_id, ObjectId

  one :profile, :class_name => 'Profile'
  validates_associated :profile
  delegate :first_name, :last_name, :to => :profile
  before_save :downcase_diaspora_handle 
  
  def downcase_diaspora_handle
    diaspora_handle.downcase!
  end

  belongs_to :owner, :class_name => 'User'

  timestamps!
  
  before_destroy :remove_all_traces
  before_validation :clean_url
  validates_presence_of :url, :profile, :serialized_public_key
  validates_uniqueness_of :diaspora_handle, :case_sensitive => false
  #validates_format_of :url, :with =>
  #  /^(https?):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*(\.[a-z]{2,5})?(:[0-9]{1,5})?(\/.*)?$/ix

  ensure_index :diaspora_handle

  scope :searchable, where('profile.searchable' => true)

  attr_accessible :profile

  def self.search(query)
    return Person.searchable.all if query.to_s.empty?
    query_tokens = query.to_s.strip.split(" ")
    full_query_text = Regexp.escape(query.to_s.strip)

    p = []

    query_tokens.each do |token|
      q = Regexp.escape(token.to_s.strip)
      p = Person.searchable.all('profile.first_name' => /^#{q}/i) \
 | Person.searchable.all('profile.last_name' => /^#{q}/i) \
 | Person.searchable.all('diaspora_handle' => /^#{q}/i) \
 | p
    end
  
    return p
  end

  def real_name
    if profile.first_name.nil? || profile.first_name.empty?
      self.diaspora_handle
    else
      "#{profile.first_name.to_s} #{profile.last_name.to_s}"
    end
  end

  def owns?(post)
    self.id == post.person.id
  end

  def receive_url
    "#{self.url}receive/users/#{self.id}/"
  end

  def public_url
    "#{self.url}public/#{self.owner.username}"
  end


  def public_key_hash
    Base64.encode64 OpenSSL::Digest::SHA256.new(self.exported_key).to_s
  end

  def public_key
    OpenSSL::PKey::RSA.new(serialized_public_key)
  end

  def exported_key
    serialized_public_key
  end

  def exported_key= new_key
    raise "Don't change a key" if serialized_public_key
    @serialized_public_key = new_key
  end

  #database calls
  def self.by_account_identifier(identifier)
    identifier = identifier.strip.downcase.gsub('acct:', '')
    self.first(:diaspora_handle => identifier)
  end

  def self.local_by_account_identifier(identifier)
    person = self.by_account_identifier(identifier)
   (person.nil? || person.remote?) ? nil : person
  end

  def self.build_from_webfinger(profile, hcard)
    return nil if profile.nil? || !profile.valid_diaspora_profile?
    new_person = Person.new
    new_person.exported_key = profile.public_key
    new_person.id = profile.guid
    new_person.diaspora_handle = profile.account
    new_person.url = profile.seed_location

    #hcard_profile = HCard.find profile.hcard.first[:href]
    Rails.logger.info("hcard: #{ hcard.inspect}")
    new_person.url = hcard[:url]
    new_person.profile = Profile.new( :first_name => hcard[:given_name],
                                      :last_name  => hcard[:family_name],
                                      :image_url  => hcard[:photo],
                                      :searchable => hcard[:searchable])

    new_person.save! ? new_person : nil
  end

  def remote?
    owner_id.nil?
  end

  def as_json(opts={})
    {
      :person => {
        :id           => self.id,
        :name         => self.real_name,
        :diaspora_handle => self.diaspora_handle,
        :url          => self.url,
        :exported_key => exported_key
      }
    }
  end
  protected

  def clean_url
    self.url ||= "http://localhost:3000/" if self.class == User
    if self.url
      self.url = 'http://' + self.url unless self.url.match(/https?:\/\//)
      self.url = self.url + '/' if self.url[-1, 1] != '/'
    end
  end

  private
  def remove_all_traces
    Post.all(:person_id => id).each { |p| p.delete }
  end
end