require 'java'

java_import com.jbidwatcher.util.config.JConfig
java_import com.cyberfox.util.platform.Path
java_import com.jbidwatcher.util.Currency
java_import com.jbidwatcher.util.Constants
java_import com.jbidwatcher.util.queue.MQFactory
java_import com.jbidwatcher.auction.AuctionEntry
java_import com.jbidwatcher.auction.server.AuctionServerManager
java_import com.jbidwatcher.ui.AuctionsManager
java_import com.jbidwatcher.ui.FilterManager
java_import com.jbidwatcher.ui.table.TableColumnController
java_import com.jbidwatcher.ui.commands.UserActions
java_import com.jbidwatcher.ui.commands.MenuCommand

puts "Loading JBidwatcher Ruby Utilities"

require 'rubygems'
dirname = File.dirname(__FILE__)
gems = if File.exists?(File.join(dirname, 'gems.jar')) || File.exists?('lib/jbidwatcher/gems.jar')
  File.expand_path(File.join(dirname, 'gems.jar'))
else
  JConfig.java_class.class_loader.resource_as_url('lib/jbidwatcher/gems.jar').to_s
end

# This is an awful hack, but if I don't do this, Windows doesn't load active_support. :(
class File
  def self.realpath(x)
    x
  end
end

require gems
ENV['GEM_PATH']="#{gems}!/"
Gem.paths = ENV
require 'digest/md5'
require 'net/http.rb'
require 'cgi'
$: << 'lib/jbidwatcher/nokogiri-1.5.2-java/lib'
require 'nokogiri'
require 'json'
require 'open-uri'
require 'ebay_parser'
require 'time'
require 'column_lookup'
require 'erb'

class JBidwatcherUtilities
  MY_JBIDWATCHER_URL = "http://my.jbidwatcher.com:9876/advanced"

  def test_basics
    # Check that the basic libraries work.
    puts "This is a test..."
    puts Digest::MD5.hexdigest('foo')

    # Check that accessing objects defined by JBidwatcher works
    c = Currency.getCurrency("$54.98")
    puts c.getValue
    puts c.fullCurrencyName

    puts "Done."
  end

  def about
    MQFactory.getConcrete("user").enqueue("FAQ")
  end

  def fire(user_event)
    MQFactory.getConcrete("user").enqueue(user_event)
  end

  def build_url(meth, hash)
    uri = "#{MY_JBIDWATCHER_URL}/#{meth}"
    url = URI.parse(uri)
    [uri, url, hash.to_param]
  end

  def post(command, hash)
    uri, url, params = build_url(command, hash)

    p = Net::HTTP::Post.new(uri)
    p.body = params
    p.content_type = 'application/x-www-form-urlencoded'

    Net::HTTP.new(url.host, url.port).start do |http|
      http.request p
    end
  end

  def report_exception(exception)
    result = post "exception", {:body => exception}
    puts result.body
    result.body
  end

  def recognize_bidpage(entry, page)
    puts entry.title
    result = post "recognize", {:body => page, :user => JConfig.queryConfiguration("my.jbidwatcher.id")}
    puts result.body
    result.body
  end

  def browse_to(id)
    entry = $auctions_manager.getEntry(id)
    entry.server.showBrowser(entry)
  end

  def notify(message)
    MQFactory.getConcrete("Swing").enqueue("NOTIFY #{message}")
  end

  def snipe(auction, amount)
    entry = auction if(auction.respond_to? :getIdentifier)
    entry ||= $auctions_manager.getEntry(auction)
    amount = Currency.getCurrency(amount) unless amount.respond_to? :fullCurrencyName
    entry.prepareSnipe(amount)
    $filter_manager.redrawEntry(entry)
  end

  def cancel_snipe(id)
    entry = $auctions_manager.getEntry(id)
    entry.cancelSnipe(false)
    $filter_manager.redrawEntry(entry)
  end

  def custom_column(column, auction)
    @columns[column].call(auction).to_s
  end

  def add_column(name, &block)
    $table_controller.add_column(name) unless @columns[name]
    @columns[name] = block
  end

  def initialize
    @columns = {}
  end

  COMMANDS = {}

  UserActions.java_class.declared_instance_methods.each do |m|
    if m.annotation_present?(MenuCommand.java_class)
      annotation = m.annotation(MenuCommand.java_class)
      COMMANDS[annotation.action] = { :name => m.name.to_sym, :arity => annotation.params } if annotation.action && annotation.action != ""
      COMMANDS[m.name.to_sym] =     { :name => m.name.to_sym, :arity => annotation.params }
    end
  end

  TRANSLATIONS = {
      'Add New' => 'Add',
      'Check For Updates' => 'Check Updates',
      'Explain Colors And Icons' => 'Help Colors'
  }

  def handle_action(action, action_manager, *params)
    do_action = "Do#{action.gsub(' ', '')}".to_sym
    pair = COMMANDS[action] || COMMANDS[do_action]

    method = pair.nil? ? do_action : pair[:name]
    arity = pair.nil? ? 0 : pair[:arity]

    # Special case params: -1 means pass in null as the sole parameter, -2 means just the auction entry.
    params, arity = {-1 => [[nil], 1], -2 => [[params[1]], 1]}[arity] if arity < 0

    if action_manager.respond_to?(method, true)
      params = [method] + params[0...arity]
      action_manager.send(*params)
    else
      JConfig.log.logMessage "Did not know how to handle #{action}"
    end
  end

  def load_scripts
    script_dir = Path.getCanonicalFile "scripts","jbidwatcher",false
    if File.exist?(script_dir) && File.directory?(script_dir)
      sd = Dir.new script_dir
      scripts = sd.reject do |filename|
        script_file = File.join(script_dir, filename)
        File.directory?(script_file) || File.extname(script_file) != '.rb'
      end

      scripts.each do |script_file|
        require File.join(script_dir, script_file)
      end
    else
      unless File.exist? script_dir
        Dir.mkdir script_dir
      end
    end
  end

  def after_startup
    require "models"
    gixen
    require 'active_support'
    require 'active_support/core_ext'
    require 'pp'
  end

  def parse(body)
    Ebay::Parser.new(body).parse
  end

  def log(msg)
    JConfig.log.logMessage msg
  end

  def get_update(auction_id, last_updated_at)
    current = (Time.now.to_f*1000).to_i
    last_int = last_updated_at.nil? ? 0 : last_updated_at.time
    lite_url = "http://www.ebay.com/itm/ws/eBayISAPI.dll?ViewItemLite&pbv=0&item=#{auction_id}"
    lite_url += "&lastaccessed=#{last_int}&lvr=0&dl=5&_=#{current}"
    body = open(lite_url).read
    result = JSON.parse(body)
    response = result['ViewItemLiteResponse']

    if response['Error'].blank?
      item = response['Item'].first
      end_date = item['EndDate']

      ends_at = Time.parse(end_date['Time'] + ' ' + end_date['Date'])
      cur_price = item['CurrentPrice']['MoneyStandard']
      ended = item['IsEnded']
      bid_count = item['BidCount']

      {
          'current_price' => cur_price,
          'end_date' => (ends_at.to_f*1000).to_i,
          'ended' => ended,
          'bid_count' => bid_count
      }
    end
  rescue => e
    log e.inspect
    return nil
  end

  def dump_hash(h)
    pp h
  end

  def gixen
    @gixen ||= begin
      dirname = File.dirname(__FILE__)
      if File.exists?(File.join(dirname, "gixen")) || File.exists?('lib/jbidwatcher/gixen')
        $:<< File.join(dirname, "gixen")
      else
        $:<< JConfig.java_class.class_loader.resource_as_url('lib/jbidwatcher/gixen').to_s
      end

      require 'gixen'

      server_prefix = Constants::EBAY_SERVER_NAME
      username = JConfig.query_configuration("#{server_prefix}.user")
      password = JConfig.query_configuration("#{server_prefix}.password")
      Gixen.new(username, password) if username != 'default'
    end
  end

  # This is just a dumping ground right now; I should change that soon.
  def get_value(entry, column)

  end

  def render_info(entry, include_events)
    InfoPresenter.new(entry, include_events).render
  end

  def render_comment(entry)
    CommentPresenter.new(entry).render
  end
end

class Presenter
  def _render(filename)
    dirname = File.dirname(__FILE__)
    canonical_template = File.join(dirname, filename)
    template = open(canonical_template).read
    @depth ||= 0
    @depth += 1
    ERB.new(template, nil, '-', "_erbout#{@depth}").result(binding).tap do
      @depth -= 1
    end
  end
end

class InfoPresenter < Presenter
  def initialize(entry, include_events)
    @entry = entry
    @include_events = include_events
  end

  def thumbnail(entry)
    if entry.thumbnail
      nail = javax.swing.ImageIcon.new(java.net.URL.new(entry.thumbnail))
      if nail.image_load_status == java.awt.MediaTracker::COMPLETE
        h = nail.icon_height
        w = nail.icon_width
        long_side = [h, w].max
        scale = 192.0 / long_side.to_f
        h = h.to_f * scale
        w = w.to_f * scale
        {url: entry.thumbnail, h: h.to_i, w: w.to_i}
      end
    end
  rescue => e
    log(e.to_s)
    nil
  end

  def render
    @thumb = thumbnail(@entry)
    _render('auction_info.html.erb')
  end
end

class CommentPresenter < Presenter
  def initialize(entry)
    @entry = entry
  end

  def render
    _render('comment.html.erb')
  end
end

# $auction_server_manager = AuctionServerManager.getInstance
# $auctions_manager = AuctionsManager.getInstance
# $filter_manager = $auctions_manager.filters
$table_controller = TableColumnController.getInstance
JBidwatcher = JBidwatcherUtilities.new

JBidwatcher.load_scripts

# case TableColumnController.CUR_BID :
#     return currentBid(aEntry);
# case TableColumnController.SNIPE_OR_MAX : return formatSnipeAndBid(aEntry);
# case TableColumnController.MAX : return aEntry.isBidOn() ? formatBid(aEntry, errorNote) :neverBid;
# case TableColumnController.SNIPE :
#     return snipeColumn(aEntry, errorNote);
# case TableColumnController.TIME_LEFT :
#     return timeLeftColumn(aEntry);
# case TableColumnController.END_DATE :
#     return endDateColumn(aEntry);
# case TableColumnController.TITLE : return XMLElement.decodeString(aEntry.getTitle());
# case TableColumnController.STATUS : return getEntryIcon(aEntry);
# case TableColumnController.THUMBNAIL :
#     return thumbnailColumn(aEntry);
# case TableColumnController.SELLER :
#     return aEntry.getSellerName();
# case TableColumnController.COMMENT :
#     String comment = aEntry.getComment();
# return(comment==null? "" :comment);
# case TableColumnController.BIDDER :
#     String bidder = aEntry.getHighBidder();
# if (bidder != null && bidder.length() != 0)
#   return bidder;
#   return "--";
#   case TableColumnController.FIXED_PRICE :
#       Currency bin = aEntry.getBuyNow();
#   if (bin.isNull())
#     return "--";
#     return bin;
#     case TableColumnController.SHIPPING_INSURANCE :
#         Currency ship = aEntry.getShippingWithInsurance();
#     if (ship.isNull())
#       return "--";
#       return ship;
#       case TableColumnController.ITEM_LOCATION :
#           return aEntry.getItemLocation();
#       case TableColumnController.BIDCOUNT :
#           if (aEntry.getNumBidders() < 0)
#             return "(FP)";
#             return Integer.toString(aEntry.getNumBidders());
#             case TableColumnController.JUSTPRICE :
#                 return aEntry.getCurrentPrice();
#             case TableColumnController.SELLER_FEEDBACK :
#                 return seller.getFeedback();
#             case TableColumnController.SELLER_POSITIVE_FEEDBACK :
#                 String fbp = seller.getPositivePercentage();
#             return (fbp == null || fbp.length() == 0) ? "--" :fbp;
#             case TableColumnController.CUR_TOTAL :
#                 return priceWithShippingColumn(aEntry);
#             case TableColumnController.SNIPE_TOTAL :
#                 return formatTotalSnipe(aEntry, errorNote);
#
#
