require 'rubygems'

gem 'main', '>= 2.8.2'
gem 'highline', '>= 1.4.0'
gem 'activerecord', '= 2.2.2'
gem 'sqlite3-ruby', '>= 1.2.1'

require 'main'
require 'highline/import'
require 'activerecord'
require 'sqlite3'
require 'htmlentities'

HighLine.track_eof = false
CLI_ROOT = File.expand_path(File.join(File.dirname(__FILE__), 'cli'))
require CLI_ROOT + '/config'
require CLI_ROOT + '/helpers'
Dir[CLI_ROOT + '/models/*.rb'].each { |m| require m }

include Twitter::CLI::Helpers

Main {
  def run
    puts "twitter [command] --help for usage instructions."
    puts "The available commands are: \n   install, uninstall, add, remove, list, change, post, befriend, defriend, follow, leave, d and timeline."
  end
  
  mode 'install' do
    description 'Creates the sqlite3 database and runs the migrations.'
    def run
      migrate
      attempt_import
      say 'Twitter installed.'
    end
  end
  
  mode 'uninstall' do
    description 'Removes the sqlite3 database. There is no undo for this.'
    def run
      FileUtils.rm(Twitter::CLI::Config[:database]) if File.exists?(Twitter::CLI::Config[:database])
      say 'Twitter gem uninstalled.'
    end
  end
  
  mode 'add' do
    description 'Adds a new twitter account to the database. Prompts for username and password.'
    argument('username', 'u') {
      optional
      description 'optional username'
    }
    argument('password', 'p') {
      optional
      description 'optional password'
    }
    
    def run
      account = Hash.new
      say "Add New Account:"
      
      # allows optional username arg
      if params['username'].given?
        account[:username] = params['username'].value
      else
        account[:username] = ask('Username: ') do |q|
          q.validate = /\S+/
        end
      end
      
      # allows optional password arg
      if params['password'].given?
        account[:password] = params['password'].value
      else
        account[:password] = ask("Password (won't be displayed): ") do |q|
          q.echo = false
          q.validate = /\S+/
        end
      end
      
      do_work do
        base(account[:username], account[:password]).verify_credentials
        Account.add(account)
        say 'Account added.'
      end
    end
  end
  
  mode 'remove' do
    description 'Removes a twitter account from the database. If username provided it removes that username else it prompts with list and asks for which one you would like to remove.'
    argument( 'username' ) { 
      optional
      description 'username of account you would like to remove' 
    }
    
    def run
      do_work do
        if params['username'].given?
          account = Account.find_by_username(params['username'].value)
        else
          Account.find(:all, :order => 'username').each do |a|
            say "#{a.id}. #{a}"
          end
          account_id = ask 'Account to remove (enter number): ' do |q|
            q.validate = /\d+/
          end
        end
        
        begin
          account = account_id ? Account.find(account_id) : account
          account_name = account.username
          account.destroy
          Account.set_current(Account.first) if Account.new_active_needed?
          say "#{account_name} has been removed.\n"
        rescue ActiveRecord::RecordNotFound
          say "ERROR: Account could not be found. Try again. \n"
        end
      end
    end
  end
  
  mode 'list' do
    description 'Lists all the accounts that have been added and puts a * by the current one that is used for posting, etc.'
    def run
      do_work do
        if Account.count == 0
          say 'No accounts have been added.' 
        else
          say 'Account List'
          Account.find(:all, :order => 'username').each do |a|
            say a 
          end
        end
      end
    end
  end
  
  mode 'change' do
    description 'Changes the current account being used for posting etc. to the username provided. If no username is provided, a list is presented and you can choose the account from there.'
    argument( 'username' ) { 
      optional
      description 'username of account you would like to switched to' 
    }
    
    def run
      do_work do
        if params['username'].given?
          new_current = Account.find_by_username(params['username'].value)
        else
          Account.find(:all, :order => 'username').each do |a|
            say "#{a.id}. #{a}"
          end
          new_current = ask 'Change current account to (enter number): ' do |q|
            q.validate = /\d+/
          end
        end
        
        begin
          current = Account.set_current(new_current)
          say "#{current} is now the current account.\n"
        rescue ActiveRecord::RecordNotFound
          say "ERROR: Account could not be found. Try again. \n"
        end
      end
    end
  end
  
  mode 'post' do
    description "Posts a message to twitter using the current account. The following are all valid examples from the command line:
    $ twitter post 'my update'
    $ twitter post my update with quotes
    $ echo 'my update from stdin' | twitter post"
    def run
      do_work do
        post = ARGV.size > 1 ? ARGV.join(" ") : ARGV.shift
        say "Sending twitter update"
        finished, status = false, nil
        progress_thread = Thread.new { until finished; print "."; $stdout.flush; sleep 0.5; end; }
        post_thread = Thread.new(binding()) do |b|
          status = base.post(post, :source => Twitter::SourceName)
          finished = true
        end
        post_thread.join
        progress_thread.join
        say "Got it! New tweet created at: #{status.created_at}\n"
      end
    end
  end

  mode 'befriend' do
    description "Allows you to add a user as a friend"
    argument('username') {
      required
      description 'username or id of twitterrer to befriend'
    }

    def run
      do_work do
        username = params['username'].value
        base.create_friendship(username)
        say "#{username} has been added as a friend. follow notifications with 'twitter follow #{username}'"
      end
    end
  end

  mode 'defriend' do
    description "Allows you to remove a user from being a friend"
    argument('username') {
      required
      description 'username or id of twitterrer to defriend'
    }

    def run
      do_work do
        username = params['username'].value
        base.destroy_friendship(username)
        say "#{username} has been removed from your friends"
      end
    end
  end
  
  mode 'follow' do
    description "Allows you to add notifications for a user (aka Follow Them)"
    argument('username') {
      required
      description 'username or id of twitterrer to follow'
    }
    
    def run
      do_work do
        username = params['username'].value
        base.follow(username)
        say "You are now following notifications from #{username}"
      end
    end
  end
  
  mode 'leave' do
    description "Allows you to turn off notifications for a user"
    argument('username') {
      required
      description 'username or id of twitterrer to leave'
    }
    
    def run
      do_work do
        username = params['username'].value
        base.leave(username)
        say "You are no longer following notifications from #{username}"
      end
    end
  end
  
  mode 'd' do
    description "Allows you to direct message a user. The following are all valid examples from the command line:
    $ twitter d jnunemaker 'yo homeboy'
    $ twitter d jnunemaker yo homeboy
    $ echo 'yo homeboy' | twitter d jnunemaker"
    argument('username') {
      required
      description 'username or id of twitterrer to direct message'
    }
    
    def run
      do_work do
        username = params['username'].value
        post = ARGV.size > 1 ? ARGV.join(" ") : ARGV.shift
        base.d(username, post)
        say "Direct message sent to #{username}"
      end
    end
  end
  
  mode 'timeline' do
    description "Allows you to view your timeline, your friends or the public one"
    argument( 'timeline' ) {
      description 'the timeline you wish to see (friends, public, me)'
      default 'friends'
    }
    option('force', 'f') {
      description "Ignore since_id and show first page of results even if there aren't new ones"
    }
    option('reverse', 'r') {
      description 'Reverse output, with the newest tweets at the top'
    }
    
    def run
      do_work do
        timeline = params['timeline'].value == 'me' ? 'user' : params['timeline'].value
        options, since_id = {}, Configuration["#{timeline}_since_id"]
        options[:since_id] = since_id if !since_id.nil? && !params['force'].given?
        reverse = params['reverse'].given? ? false : true
        cache = [:friends, :user].include?(timeline)
        collection = base.timeline(timeline.to_sym, options)
        output_tweets(collection, {:cache => cache, :since_prefix => timeline, :reverse => reverse})
      end
    end
  end
  
  mode 'replies' do
    description 'Allows you to view all @replies sent to you'
    option('force', 'f') {
      description "Ignore since_id and show first page of replies even if there aren't new ones"
    }
    
    def run
      do_work do
        options, since_id = {}, Configuration["replies_since_id"]
        options[:since_id] = since_id if !since_id.nil? && !params['force'].given?
        collection = base.replies(options)
        output_tweets(collection, {:since_prefix => 'replies'})
      end
    end
  end
  
  mode 'clear_config' do
    def run
      do_work do
        count = Configuration.count
        Configuration.destroy_all
        say("#{count} configuration entries cleared.")
      end
    end
  end
  
  mode 'open' do
    description 'Opens the given twitter user in a browser window'
    argument('username') {
      required
      description "username or id of twitterrer who's page you would like to see"
    }
    
    def run
      `open http://twitter.com/#{params['username'].value}`
    end
  end
}
