require 'ostruct'
require 'csv'
require 'yaml'
require 'rubygems'
require 'mechanize'
@agent = Mechanize.new
@agent.user_agent_alias = 'Linux Mozilla'

# Settings <CHANGE!>
IMDB_ID = 'ur'
IMDB_USERNAME = ''
IMDB_PASSWORD = ''
MOVIEPILOT_USERNAME = ''
MOVIEPILOT_PASSWORD = ''

module ::IMDb
  URL = 'http://www.imdb.com'

  LOGIN_URL = 'https://secure.imdb.com/oauth/login?show_imdb_panel=1'

  RE_ID = %r{(?<id>(?<type>tt|nm)\d+)}
  # xpath to search result urls
  XPATH_FIND_RESULTS = '.findResult td:first a/@href' 

  # return the ID of the first movie or name (actor, etc.) found
  def self.find_id(q)
    agent = create_agent
    page = agent.get URL + '/find?q=' + CGI.escape(q)
    urls = page.search XPATH_FIND_RESULTS
    return if not urls
    urls.map {|url| $1 if url.value.match RE_ID }.compact.first
  end

  def self.create_agent
    a = Mechanize.new
    a.user_agent_alias = 'Linux Firefox'
    return a
  end

  def self.load(id)
    if id.match(RE_ID)[:type] == 'tt'
      Movie.new id
    else
      Name.new id
    end
  end

  def self.login(username, password)
    begin
      puts 'IMDb login using %s' % [username]
      agent = create_agent
      page = agent.get(LOGIN_URL)
      form = page.forms.first
      form.login = username
      form.password = password
      page = form.submit
      puts 'IMDb login redirect to %s' % [page.uri.to_s]
      if page.uri.to_s.match /closer/
        agent
      else
        nil
      end
    rescue
      puts $!.to_s
      puts $@.join '\n'
      nil
    end
  end
end

#login imdb:
@agent = IMDb::login(IMDB_USERNAME, IMDB_PASSWORD)

#
# export imdb (so it only rates once)
#
IMDB_URL = 'http://www.imdb.com/list/export?list_id=ratings&author_id=' + IMDB_ID
RATINGS_CSV = './ratings.csv'
@ratings = []
if not File.exists? RATINGS_CSV
  puts "Export Ratings from imdb.com..."
  ratings_csv = @agent.get(IMDB_URL).body.split('\n')
  IO.write(RATINGS_CSV, ratings_csv.join('\n'))
else
  puts "Export Ratings (cached)"
end
ratings_csv = IO.readlines RATINGS_CSV

ratings_csv.each do |row|
  row = CSV.parse(row).first
  next if not row.first.match /\d+/

  rating = OpenStruct.new
  rating.id = row[1] # .gsub(/tt/,'')
  rating.title = row[5]
  rating.vote = row[8]
  type = row[6]
  if type.match /Series/
    rating.type = 'series'
  else
    rating.type = 'movies'
  end

  @ratings << rating
end
puts "Exported #{@ratings.length} ratings."


#
# import moviepilot
#
URL = 'http://www.moviepilot.de'
# Login
puts "Login to moviepilot"
page = @agent.get URL+'/login'
login_form = page.form_with(:id => 'new_session')
login_form.username = MOVIEPILOT_USERNAME
login_form.password = MOVIEPILOT_PASSWORD
login_form.submit

def search(type, q)
  page = @agent.get URL+'/searches', {:utf8 => "\u2713", :type => type, :q => q}
  links = page.search('.movies.list-results li h3 a')
  if links and links.length > 0
    links.map do |link|
      [URL+link['href'], link['title']]
    end
  else
    []
  end
end

@idCache = {}
ID_CACHE='./moviepilot_url.cache'
@idCache = YAML::load(IO.read(ID_CACHE)) if File.exists? ID_CACHE
def setId(url, id)
  @idCache[url] = id
  IO.write(ID_CACHE, YAML::dump(@idCache))
end
def getId(url)
  if not @idCache.has_key? url
    page = @agent.get url
    if page.body.match /kvmovie=tt(\d+)/
      setId(url, $1.to_i)
    end
  end

  @idCache[url]
end

# gather and cache the users ratings history
@pilotRatings = {}
def fetchPages(page)
  loop do
    puts "Parse ratings history page at moviepilot #{page.uri}"
    parseRatings(page)

    # next page
    next_page = page.search '.next a/@href'
    if next_page and not next_page.empty?
      page = @agent.get URL + next_page.first.value
    else
      break
    end
  end
end
def parseRatings(page)
  linkRows = page.search('td.plain-list-movie a').to_a
  ratingRows = page.search('td.plain-list-rating/text()').to_a
  linkRows.each_index do |i|
    rating = ratingRows[i].to_s.strip
    if rating.match /^(\d+\.\d+)/
      url = URL+linkRows[i]['href'].to_s
      title = linkRows[i]['title'].to_s # unused
      rating = $1.to_f.round.to_i
      puts page.uri.to_s+'<= rating => '+rating.to_s

      @pilotRatings[url] = rating
    end
  end
end
page = @agent.get URL+'/my_movies'
fetchPages(page)
fetchPages(@agent.click(page.link_with(:href=>/rated\/series/)))
puts "Retreived Ratings for #{@pilotRatings.values.length} movies/series"


def rating_exists?(imdb_id)
  sel = @ratings.select do |rating|
    rating.id == imdb_id
  end
  return (not sel.empty?)
end

# rate:
@pilotRatings.each_pair do |url, rating|
  imdb_id = 'tt%07d' % getId(url).to_i
  imdb_url = 'http://www.imdb.com/title/' + imdb_id + '/reference'

  puts 'moviepilot rating %s -> %s' % [imdb_id.inspect, rating.inspect]

  if rating_exists? imdb_id
    puts 'already at imdb'
    next
  end

puts 'rating..'

  begin
    page = @agent.get imdb_url
    link = page.search '//a[contains(@href, "vote?v=%d")]/@href' % [rating]
    if not link
      puts 'the rating link could not be found'
      next
    end

    @agent.get 'http://www.imdb.com/title/' + imdb_id + '/' + link.first.value
    puts 'rated.'
  rescue
    puts 'error rating!'
    puts $!.to_s
    puts $@.join '\n'
    puts
  end

end