#!/usr/bin/env ruby
$:.unshift File.dirname(__FILE__) + "/../../lib" 
require 'rubygems'
require 'camping'
require 'camping/db'
require 'camping/session'
require 'reststop'
require 'httpauth'

Camping.goes :Ctd

module Ctd
  #http://rubyforge.org/pipermail/camping-list/2008-February/000589.html
  include Camping::Session
  include HTTPAuth::Digest
  
  REALM = "ctd"
  class Unauthorized < RuntimeError; end

  # call this at the start of methods that require authentication
  def authenticate
    raise Unauthorized unless @user
  end

  def service(*a)
    auth_h = @env["HTTP_AUTHORIZATION"]

    begin
      if auth_h
        credentials = Credentials.from_header(auth_h)
        user = credentials.h[:username]

        begin
          pass = password_for_user(user)
        rescue NameError
          raise "define #password_for_user on your app module"
        end

        if pass and
            credentials.validate(:password => pass, :method => @method.upcase)
          @user = user

          auth_info = AuthenticationInfo.from_credentials credentials
          @headers["Authentication-Info"] = auth_info.to_header
        end
      end
      
      super()
    rescue HTTPAuth::UnwellformedHeader
      # they probably sent eg. a Basic Authenticate header
      # just ignore it instead of exploding
    end

    super(*a)
  rescue Unauthorized
    @status = 401
    challenge = Challenge.new :realm => REALM, :qop => ["auth"]
    @headers["WWW-Authenticate"] = challenge.to_header

    @body = authentication_failed

    self
  end

  # override this for a nicer error message
  def authentication_failed
    @headers["Content-Type"] = "text/plain"

    "you are not authorized."
  end
  
  def password_for_user(username)
    Ctd::Models::User.find( :first, :conditions => ['username = ?', username]).password
  end
end

module Ctd::Models
    class Device < Base; end
    class User < Base; 
      validates_uniqueness_of :username
    end
    class CreateTheBasics < V 1.0
      def self.up
        create_table :ctd_devices do |t|
          t.column :channel,  :integer, :null => false
          t.column :on?, :boolean, :default => true
        end
        create_table :ctd_users do |t|
          t.column :username, :string
          t.column :password, :string
        end
        User.create :username => 'admin', :password => 'camping'
        (1..8).each {|n| Device.create :channel => n}
      end
      def self.down
        drop_table :ctd_users
        drop_table :ctd_devices
      end
    end
end

module Ctd::Controllers
  class NotFound
    def get(p)
      @status = 404
      div do
        h1 'Lo Sentimos'
        h2 "Todos los circuitos están ocupados"
        h3 do 
          text("Por favor ")
          text( a('cuelgue', :href => R(Index)))
          text( "y deje de marcar #{p}")
        end
      end
    end
  end
  
  class Info < R '/info/(\d+)', '/info/(\w+)/(\d+)', '/info', '/info/(\d+)/(\d+)/(\d+)/([\w-]+)'
    def get(*args)
      div do
        code args.inspect; br; br
        code @env.inspect; br
        code "Link: #{R(Info, 1, 2)}"
      end
    end
  end
  
  class Index < R '/'
    def get
      redirect "devices"
    end
  end
    
  class Devices < REST 'devices'
    # get /devices/1
    def read(channel)
      authenticate
      #return redirect R(Index) if @state.user_id.blank?
      begin
        @device = Device.find channel
      rescue
        @device = nil
      end
      render :device
    end
    
    # get /devices
    def list
      authenticate
      @device = nil
      render :device
    end
  end
end

Markaby::Builder.set(:indent, 2)

module Ctd::Views
  def layout
    html do
      head do
        title 'Call To Device'
        link  :rel => 'stylesheet', :type => 'text/css',
              :href => '/styles.css', :media => 'screen'
      end
      body do
        h1.header { a 'Call To Device', :href => R(Index) }
        div.content do
          self << yield
        end
      end
    end
  end
  
  def device
    if @device
      p "Usted ha seleccionado el dispositivo #{@device.channel}"
    else
      p "Seleccione el dispositivo a administrar"
    end
  end
end


def Ctd.create
  Camping::Models::Session.create_schema
  Ctd::Models.create_schema :assume => (Ctd::Models::Device.table_exists? ? 1.0 : 0.0)
end

if __FILE__ == $0
  require 'webrick/httpserver'
  require 'webrick/https'
  require 'camping/webrick'

  Camping::Models::Base.establish_connection :adapter  => "sqlite3", :database => "ctd.db"
  Ctd.create
  s = WEBrick::HTTPServer.new(
    :SSLEnable    => true,
    :SSLCertName => [ ["C","DO"], ["O","CTD.Com"], ["CN", "localhost"] ],
    :BindAddress  => "0.0.0.0", 
    :Port         => 3301
    )
  s.mount "/", WEBrick::CampingHandler, Ctd

  # This lets Ctrl+C shut down your server
  trap(:INT) do
    s.shutdown
  end

  s.start
end