'use strict';


var YAMLException = require('./exception');


// TODO: Add tag format check.
function Type(tag, options) {
  options = options || {};

  this.tag    = tag;
  this.loader = options['loader'] || null;
  this.dumper = options['dumper'] || null;

  if (null === this.loader && null === this.dumper) {
    throw new YAMLException('Incomplete YAML type definition. "loader" or "dumper" setting must be specified.');
  }

  if (null !== this.loader) {
    this.loader = new Type.Loader(this.loader);
  }

  if (null !== this.dumper) {
    this.dumper = new Type.Dumper(this.dumper);
  }
}


Type.Loader = function TypeLoader(options) {
  options = options || {};

  this.kind     = options['kind']     || null;
  this.resolver = options['resolver'] || null;

  if ('string' !== this.kind &&
      'array'  !== this.kind &&
      'object' !== this.kind) {
    throw new YAMLException('Unacceptable "kind" setting of a type loader.');
  }
};


function compileAliases(map) {
  var result = {};

  if (null !== map) {
    Object.keys(map).forEach(function (style) {
      map[style].forEach(function (alias) {
        result[String(alias)] = style;
      });
    });
  }

  return result;
}


Type.Dumper = function TypeDumper(options) {
  options = options || {};

  this.kind         = options['kind']         || null;
  this.defaultStyle = options['defaultStyle'] || null;
  this.instanceOf   = options['instanceOf']   || null;
  this.predicate    = options['predicate']    || null;
  this.representer  = options['representer']  || null;
  this.styleAliases = compileAliases(options['styleAliases'] || null);

  if ('undefined' !== this.kind &&
      'null'      !== this.kind &&
      'boolean'   !== this.kind &&
      'integer'   !== this.kind &&
      'float'     !== this.kind &&
      'string'    !== this.kind &&
      'array'     !== this.kind &&
      'object'    !== this.kind &&
      'function'  !== this.kind) {
    throw new YAMLException('Unacceptable "kind" setting of a type dumper.');
  }
};


module.exports = Type;
