###
Bongo.js
Unfancy models for MongoDB

(c) 2011 Koding, Inc.

@class: bongo
@description: the main klass of the library.
@author: Christopher Thorn <chris@koding.com>
###
module.exports = class bongo
  # core
  url = require 'url'
  fs = require 'fs'
  {EventEmitter} = require 'events'
  # client-side boilerplate
  bongoClient = require 'bongo-client'
  # contrib
  # i am loving:
  @mongo = require 'mongoskin'
  # kudos also to:
  dnode = require 'dnode'
  # lib
  # the base klass of the library:
  @Model = Model = require './model'
  # the rest of the basics:
  @Subcollection = require './subcollection'
  @ObjectId = require './objectid'
  @JsPath = require './jspath'
  @Inflector = require './inflector'
  @Validator = require './validator'
  @Plugin = require './plugin'
  @TypeChecker = require './typechecker'
  {extend} = require './util'
  {BongoError} = require './errortypes'
  clientCode_ = null
  globals_ = {}

  @Client = Client = require './client'

  getDelegatedPrototypeInterface_ =(constructor, methodName, client)->
    (data, args...)->
      instance = constructor.sharedInstances[data.bongo_?.instanceId]
      if instance?
        instance.set data
      else
        instance = new constructor data
      if client
        constructor::[methodName].apply instance, [client].concat args
      else
        constructor::[methodName].apply instance, args
      
  
  getClient =(conn)-> new Client conn

  api =(remote, conn)->
    exposeClientApi:(api)->
      console.log remote

    fetchApi:(callback)->
      api = for own name, constructor of Model.sharedConstructors
        {static, instance} = constructor.getSharedMethods()
        staticMethods = {}
        instanceMethods = {}
        client = getClient conn
        for methodName in static
          try
            method = constructor[methodName]
            boundMethod =
              if method.securityIsEnabled
                method.bind constructor, client
              else
                method.bind constructor
            staticMethods[methodName] = boundMethod
          catch e
            throw new BongoError \
              """
              Shared method #{methodName} could not be bound.
              """
        for methodName in instance
          instanceMethods[methodName] =
            getDelegatedPrototypeInterface_ constructor, methodName, (client if constructor::[methodName].securityIsEnabled)
        {name, staticMethods, instanceMethods}
      callback api, globals_
  
  @secure =(fn)->
    fn.securityIsEnabled = yes
    fn
  
  @expose =(source)->
    globals_[key] = val for own key, val of source
    @

  @setClient =(overload)->
    Model.setClient overload
    @

  @listen =(server, options={})->
    {client} = options
    client or= '/bongo.js'
    dnode(api).listen server
    if server instanceof EventEmitter
      listeners = server.listeners 'request'
      server.removeAllListeners 'request'
      server.on 'request', (req, res)->
        {pathname} = url.parse req.url
        if pathname is client
          if clientCode_
            res.writeHead 200, 'Content-Type': 'text/javascript'
            res.end clientCode_
          else
            fs.readFile "#{bongoClient.browserPath}#{client}", (err, source)->
              if err
                throw err
                res.writeHead 404
                res.end "404 - browser code could not be loaded."
              else
                res.writeHead 200, 'Content-Type': 'text/javascript'
                res.end clientCode_ = source
        else
          listener.call @, req, res for listener in listeners
    @