 # MIT License
 ###
 
+q = require "q"
+url = require "url"
+https = require "https"
 crypto = require "crypto"
-
+querystring = require "querystring"
+
+oauth_req_path = "/oauth/authorize"
+oauth_access_path = "/oauth/access_token"
+oauth_proto = "https" 
+
+code_regex = /^[a-z0-9]{20}$/gi
+code_regex.compile code_regex
+
+#Stuff for the standalone use case (used by express/connect functionality)
 class PersonalApp
     ###
     PersonalApp is the central class to the library.  Instantiate it to access the Personal API.
     ###
     
-    constructor: (@config) ->
+    constructor: (config) ->
         ###
         config:
             client_id: string - <client id> (required)
             client_secret: string - <client secret> (required)
-        ###
-        @_state = {}
-        @_access = {}
+            sandbox: boolean - use sandbox if true and production if false (default: false)
+        ###
+        @_config = config
+        @_config.hostname = "#{if config.sandbox then "api-sandbox" else "api"}.personal.com"
     
     get_auth_request_url: (options) ->
         ###

        redir_url_obj = url.parse options.redirect_uri, true
        redir_url_obj.search = undefined
        redir_url_obj.query.state = state_param
        @_state[state_param] = url.format(redir_url_obj)
        
        #create url object for user redirect
        if options.sandbox
            urlObj = url.parse("https://api-sandbox.personal.com/oauth/authorize", true)
        else
            urlObj = url.parse("https://api.personal.com/oauth/authorize", true)
        urlObj.search = undefined
        urlObj.query =
            client_id: @config.client_id
            response_type: "code"
            redirect_uri: @_state[state_param]
            scope: options.scope.to_s()
            update: (update == false ? false : true)
        return urlObj

    get_access_token_auth: (code, state, callback) ->
        ###
        Get the access token for Personal API access using authorization code flow

        code: string - code returned in querystring of callback url (required)
        state: string - state parameter return from query string of callback url (required)
        callback: function - function(access_token){console.log(access_token);} (required)
        ###

        #run post
        #place returned infos into @_access
        #run callback(access_token)


    get_client: (access_code) ->
        ###

        ###

class PersonalClient
    ###
    Client 
    ###

class PersonalScope
    ###

        ###
        return @to_s()

#Stuff for the connect/express use case
connect_opts = 
    update: true
    sandbox: false

connect_curr_req_url = do ->
    _url = "init_val"
    ret_val = 
        get: -> return _url
        set: (new_url) -> _url = new_url

PersonalConnectOptions = (options) ->
    ###
    #Add all options to the connect/express options for the Personal library
    #
    #options:
    #   client_id:
    #   client_secret:
    #   scope:
    #   update: 
    #   sandbox:
    ###
    connect_opts[key] = val for key,val of options

PersonalHelpers = (app) ->
    app.locals
        auth_req_url: -> return connect_curr_req_url.get()
            
PersonalMiddleware = (req, res, next) ->
    #put logout fn in the request
    req.personal =
        logout: () ->
            req.session?.personal = logged_in: false
    
    #check that we have session and init it
    return next(new Error "session middleware not loaded") if not req.session? 
    req.session.personal = {} if not req.session.personal?
    req.personal.logout() if not req.personal?
    sess = req.session.personal

    #we already have a valid session
    if sess.access_token? and sess.refresh_token? and sess.expiration?
        req.personal.logged_in = true
        req.personal.client = new PersonalClient
            access_token: sess.access_token
            refresh_token: sess.refresh_token
            expiration: sess.expiration
        return next()
    app = new PersonalApp connect_opts

    #we are at the callback url
    if req.query.code? and req.query.state? and req.query.personal?
        if sess.state? and sess.state == req.query.state and sess.redirect_uri?
            #do access token stuff
            promise = app.get_access_token_auth
                code: req.query.code
                state: req.query.state
                redirect_url: sess.redirect_url
            promise.then (access_obj) ->
                sess[key] = val for key,val of access_obj
                sess.client = new PersonalClient access_obj
                next()
            ,(err) ->
                next(err)
            return
    
    #we need to create the url for login and auth
    new_redir_uri = url.parse "#{req.protocol}://#{req.headers.host}#{req.url}", true
    new_redir_uri.search = ""
    new_redir_uri.query.personal = true
    auth_req_obj = app.get_auth_request_url
        scope: connect_opts.scope
        update: connect_opts.update
        sandbox: connect_opts.sandbox
        redirect_uri: url.format new_redir_uri
    connect_curr_req_url.set auth_req_obj.url
    #    console.log connect_curr_req
    sess.state = auth_req_obj.state
    sess.redirect_uri = auth_req_obj.redirect_uri
    next()

#export stuff
exports.Options = PersonalConnectOptions
exports.Helpers = PersonalHelpers
exports.Middleware = PersonalMiddleware
exports.App = PersonalApp
exports.Scope = PersonalScope
