'use strict'

module.exports = function (sunstone) {

  /**
   * Plugin
   */
  sunstone.plugin('Server', {
    version: '0.0.0'
    // requires: ['Data']
  })

  /**
   * Module dependencies
   */
  .require([
    'express'
  ])

  /**
   * Settings
   */
  .factory('Settings', function (Model, Initializer, argv, mkdirp, fs, path, crypto) {

    class Settings extends Model {

      static get schema () {
        return {
          host: {
            type: 'string',
            set: Settings.set('host', 'localhost')
          },
          port: {
            type: 'number',
            set: Settings.set('port', 3000, parseInt)
          },
          redis: {
            type: 'object',
            properties: {
              host: {
                type: 'string',
                set: Settings.set('redis-host', 'localhost')
              },
              port: {
                type: 'number',
                set: Settings.set('redis-port', 6379, parseInt)
              }
            }
          },
          cookie_secret: {
            type: 'string',
            default: () => {
              return crypto.randomBytes(10).toString('hex')
            }
          }
        }
      }

      /**
       * Setter
       *
       * Looks for values in command line options, environment variables, and the source
       * object (config file), in that order. If none are found, a default value is set.
       */
      static set (key, defaultValue, formatter) {
        return function (source) {
          let value =
            argv[key] ||
            process.env[key.toUpperCase().replace('-', '_')] ||
            source[key] ||
            defaultValue

          Initializer.setDeepProperty(
            this,
            key.split('-').slice(-1),
            formatter ? formatter(value) : value
          )
        }
      }

      /**
       * Read
       */
      static read (filepath) {
        let writeAfterValidate = false

        try {
          // attempt to load and parse the given file
          var data = this.deserialize(fs.readFileSync(filepath))
        } catch (error) {
          // ignore error due to non-existing file
          if (error.code !== 'ENOENT') { throw error }

          // indicate the config should be written to
          // filepath after validation
          writeAfterValidate = true
        }

        // instantiate a config instance
        let settings = new Settings(data)

        // validate
        let validation = settings.validate()
        if (!validation.valid) {
          console.log(validation)
          process.exit(1)
        }

        // write config to file if indicated
        if (writeAfterValidate) {
          settings.write(filepath)
        }

        // return the configuration
        return settings
      }

      /**
       * Write
       */
      write (filepath) {
        let data = Settings.serialize(this)
        mkdirp.sync(path.dirname(filepath))
        fs.writeFileSync(filepath, data)
      }

      /**
       * Serialize
       */
      static serialize (obj) {
        return JSON.stringify(obj, false, 2)
      }

      /**
       * Deserialize
       */
      static deserialize (data) {
        try {
          return JSON.parse(data)
        } catch (error) {
          throw (error)
        }
      }

    }

    return Settings
  })

  /**
   * settings
   */
  .factory('settings', function (Settings,path) {
    return Settings.read(path.join(process.cwd(), 'settings.json'))
  })

  /**
   * server
   */
  .factory('server', function (express,settings) {
    let server = express()
    // build up the server
    return server
  })

}


@@ -1314,23 +1314,16 @@
  and the
- source
 %0A       
@@ -1323,16 +1323,23 @@
        *
+ source
  object 
@@ -1396,16 +1396,25 @@
  default
+%0A       *
  value i
@@ -3611,16 +3611,17 @@
 press()%0A
+%0A
     // b
@@ -3663,11 +3663,557 @@
 r%0A  %7D)%0A%0A
+  /**%0A   * Router%0A   */%0A  .factory('Router', function (express, server) %7B%0A    let Router = express.Router%0A%0A    Router.mount = function () %7B%0A      server.use(this)%0A    %7D%0A%0A    Router.unmount = function () %7B%0A      let stack = server._router.stack%0A      let index = stack.indexOf(this)%0A      stack.splice(index, 1)%0A    %7D%0A%0A    return Router%0A  %7D)%0A%0A  /**%0A   * Status%0A   */%0A  .router('status', function (Router) %7B%0A    let router = Router()%0A%0A    router.get('/', function (req, res, next) %7B%0A      res.json(%7B status: 'OK' %7D)%0A    %7D)%0A%0A    return router%0A  %7D)%0A%0A
 %7D%0A%0A

add mount and unmount methods to Express router