var JsonRpcAbstract = require('./JsonRpcAbstract.js').JsonRpcAbstract;
var Types = require('../common/Types.js');

/**
 * @class JsonRpcError
 * @extends JsonRpcAbstract
 * @requires Class
 * @requires JsonRpcAbstract
 *
 * @param {Number} code Number error code
 * @param {String} message error message
 * @param {Object} data additional error data
 */
var JsonRpcError = function (/*data|code, message, data*/) {
    this._code = null;
    this._message = null;
    this._data = null;

    JsonRpcAbstract.apply(this, arguments);
};

JsonRpcError.prototype = Object.create(JsonRpcAbstract.prototype);

JsonRpcError.prototype._init = function (args) {
    if (Types.isNumber(args[0])) {
        this.setCode(args[0]);
    } else {
        throw new Error(JsonRpcAbstract.Exceptions.INVALID_JSON_RPC);
    }

    if (Types.isString(args[1])) {
        this.setMessage(args[1]);
    } else {
        throw new Error(JsonRpcAbstract.Exceptions.INVALID_JSON_RPC);
    }

    if (args[2]) {
        this.setData(args[2]);
    }
};

JsonRpcError.prototype._parse = function (json) {
    return [
        json.code,
        json.message,
        json.data
    ];
};

/**
 * sets error code
 * 
 * @param {Number} code error code
 */
JsonRpcError.prototype.setCode = function (code) {
    if (!Types.isNumber(code)) {
        throw new Error("Code must be a Number!");
    }
    this._code = code;

    return this;
};

/**
 * gets error code
 * 
 * @returns {Number}
 */
JsonRpcError.prototype.getCode = function () {
    return this._code;
};

/**
 * sets error message
 * 
 * @param {String} message error message
 * @returns {JsonRpcError}
 */
JsonRpcError.prototype.setMessage = function (message) {
    if (!Types.isString(message)) {
        throw new Error("Message must be a String!");
    }

    this._message = message;

    return this;
};

/**
 * gets error message
 * 
 * @returns {String}
 */
JsonRpcError.prototype.getMessage = function () {
    return this._message;
};

/**
 * sets error data
 * 
 * @param {Object} data error data
 */
JsonRpcError.prototype.setData = function (data) {
    if (data instanceof JsonRpcError) {
        this._data = data.toJson();
    } else {
        this._data = data;
    }

    return this;
};

/**
 * gets error data
 * 
 * @returns {Object}
 */
JsonRpcError.prototype.getData = function () {
    return this._data;
};

/**
 * returns properties as json
 * 
 * @returns {Object}
 */
JsonRpcError.prototype.toJson = function () {
    var data = {
        code: this._code,
        message: this._message
    };

    if (this._data) {
        data.data = this._data;
    }

    return data;
};

/**
 * creates new instance based on the given instance
 * factory method
 * 
 * @static
 * 
 * @param {JsonRpcError} jsonRpcError
 * @returns {JsonRpcError}
 */
JsonRpcError.factory = function (jsonRpcError) {
    if (!(jsonRpcError instanceof JsonRpcError)) {
        throw JsonRpcError.Exceptions.WRONG_CLASS;
    }

    var factory = new JsonRpcError(jsonRpcError.getCode(), jsonRpcError.getMessage());

    return factory;
};

/**
 * @static
 * @constant
 * @namespace
 */
JsonRpcError.Exceptions = {};
/**
 * @static
 * @constant
 */
JsonRpcError.Exceptions.WRONG_CLASS = 'Given something is not a instance of JsonRpcError class';

exports.JsonRpcError = JsonRpcError;
