/* ================================================================
 * webdriver-dfn-error-code by xdf(xudafeng[at]126.com)
 *
 * first created at : Sat Feb 20 2016 15:52:03 GMT+0800 (CST)
 *
 * ================================================================
 * Copyright  xdf
 *
 * Licensed under the MIT License
 * You may not use this file except in compliance with the License.
 *
 * ================================================================ */

'use strict';

const codes = {
  Success: {
    code: 0,
    description: 'The command executed successfully.'
  },
  NoSuchDriver: {
    code: 6,
    description: 'A session is either terminated or not started'
  },
  NoSuchElement: {
    code: 7,
    description: 'An element could not be located on the page using the given search parameters.'
  },
  NoSuchFrame: {
    code: 8,
    description: 'A request to switch to a frame could not be satisfied because the frame could not be found.'
  },
  UnknownCommand: {
    code: 9,
    description: 'The requested resource could not be found, or a request was received using an HTTP method that is not supported by the mapped resource.'
  },
  StaleElementReference: {
    code: 10,
    description: 'An element command failed because the referenced element is no longer attached to the DOM.'
  },
  ElementNotVisible: {
    code: 11,
    description: 'An element command could not be completed because the element is not visible on the page.'
  },
  InvalidElementState: {
    code: 12,
    description: 'An element command could not be completed because the element is in an invalid state (e.g. attempting to click a disabled element).'
  },
  UnknownError: {
    code: 13,
    description: 'An unknown server-side error occurred while processing the command.'
  },
  ElementIsNotSelectable: {
    code: 15,
    description: 'An attempt was made to select an element that cannot be selected.'
  },
  JavaScriptError: {
    code: 17,
    description: 'An error occurred while executing user supplied !JavaScript.'
  },
  XPathLookupError: {
    code: 19,
    description: 'An error occurred while searching for an element by XPath.'
  },
  Timeout: {
    code: 21,
    description: 'An operation did not complete before its timeout expired.'
  },
  NoSuchWindow: {
    code: 23,
    description: 'A request to switch to a different window could not be satisfied because the window could not be found.'
  },
  InvalidCookieDomain: {
    code: 24,
    description: 'An illegal attempt was made to set a cookie under a different domain than the current page.'
  },
  UnableToSetCookie: {
    code: 25,
    description: 'A request to set a cookie\'s value could not be satisfied.'
  },
  UnexpectedAlertOpen: {
    code: 26,
    description: 'A modal dialog was open, blocking this operation'
  },
  NoAlertOpenError: {
    code: 27,
    description: 'An attempt was made to operate on a modal dialog when one was not open.'
  },
  ScriptTimeout: {
    code: 28,
    description: 'A script did not complete before its timeout expired.'
  },
  InvalidElementCoordinates: {
    code: 29,
    description: 'The coordinates provided to an interactions operation are invalid.'
  },
  IMENotAvailable: {
    code: 30,
    description: 'IME was not available.'
  },
  IMEEngineActivationFailed: {
    code: 31,
    description: 'An IME engine could not be started.'
  },
  InvalidSelector: {
    code: 32,
    description: 'Argument was an invalid selector (e.g. XPath/CSS).'
  },
  SessionNotCreatedException: {
    code: 33,
    description: 'A new session could not be created.'
  },
  MoveTargetOutOfBounds: {
    code: 34,
    description: 'Target provided for a move action is out of bounds.'
  }
};

const errors = {};

Object.keys(codes).map(function(name) {
  const defaultMsg = codes[name]['description'];
  errors[name] = function(msg) {
    this.name = name;
    this.message = msg || defaultMsg;
  }
  errors[name].prototype = Error.prototype;
});

errors['NotImplementedError'] = function(msg) {
  this.name = 'NotImplementedError';
  this.message = msg || 'The method is not implemented yet.';
}

errors['NotImplementedError'].prototype = Error.prototype;

errors['NoContextError'] = function(msg) {
  this.name = 'NoContextError';
  this.message = msg || 'The Context does not exist.';
}

errors['NoContextError'].prototype = Error.prototype;

exports.codes = codes;
exports.errors = errors;
exports.getErrorByCode = function(code) {
  var error = null;

  Object.keys(codes).forEach(function(item) {
    if (codes[item].code === code) {
      error = item;
    }
  });
  return error;
};

@@ -3721,113 +3721,65 @@
 %7D;%0A%0A
-Object.keys(codes).map(function(name) %7B%0A  const defaultMsg = codes%5Bname%5D%5B'description'%5D;%0A  errors%5Bname%5D =
+function customizeError(errorName, defaultMsg) %7B%0A  return
  fun
@@ -3807,17 +3807,22 @@
 .name = 
-n
+errorN
 ame;%0A   
@@ -3862,24 +3862,48 @@
 ;%0A  
-%7D%0A  errors%5Bname%5D
+  Object.setPrototypeOf(this.constructor
 .pro
@@ -3900,34 +3900,33 @@
 ructor.prototype
- =
+,
  Error.prototype
@@ -3929,47 +3929,95 @@
 type
-;%0A%7D);%0A%0Aerrors%5B'NotImplementedError'%5D = 
+);%0A    Error.captureStackTrace(this, this.constructor);%0A  %7D;%0A%7D%0A%0AObject.keys(codes).map(
 func
@@ -4025,115 +4025,119 @@
 ion(
-msg
+name
 ) %7B%0A  
-this.name = 'NotImplementedError';%0A  this.message = msg %7C%7C 'The method is not implemented yet.'
+const defaultMsg = codes%5Bname%5D%5B'description'%5D;%0A  errors%5Bname%5D = customizeError(name, defaultMsg)
 ;%0A%7D
+);
 %0A%0Aer
@@ -4167,224 +4167,178 @@
 or'%5D
-.prototype = Error.prototype;%0A%0Aerrors%5B'NoContextError'%5D = function(msg) %7B%0A  this.name = 'NoContextError';%0A  this.message = msg %7C%7C 'The Context does not exist.';%0A%7D%0A%0Aerrors%5B'NoContextError'%5D.prototype = Error.prototype
+ = customizeError('NotImplementedError', 'The method is not implemented yet.');%0Aerrors%5B'NoContextError'%5D = customizeError('NoContextError', 'The Context does not exist.')
 ;%0A%0Ae

Add stacktrace and rewrite error factory