// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

var resolveModule = function(names, mod, root) {
  if (names.length == 0) {
    if (typeof mod.current != "string") {
      throw ["error","invalid_require_path",
        'Must require a JavaScript string, not: '+(typeof mod.current)];
    }
    return {
      current : mod.current,
      parent : mod.parent,
      id : mod.id,
      exports : {}
    };
  }
  // we need to traverse the path
  var n = names.shift();
  if (n == '..') {
    if (!(mod.parent && mod.parent.parent)) {
      throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
    }
    return resolveModule(names, {
      id : mod.id.slice(0, mod.id.lastIndexOf('/')),
      parent : mod.parent.parent,
      current : mod.parent.current
    });
  } else if (n == '.') {
    if (!mod.parent) {
      throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
    }
    return resolveModule(names, {
      parent : mod.parent,
      current : mod.current,
      id : mod.id
    });
  } else if (root) {
    mod = {current : root};
  }
  if (mod.current[n] === undefined) {
    throw ["error", "invalid_require_path", 'Object has no property "'+n+'". '+JSON.stringify(mod.current)];
  }
  return resolveModule(names, {
    current : mod.current[n],
    parent : mod,
    id : mod.id ? mod.id + '/' + n : n
  });
};

var Couch = {
  // moving this away from global so we can move to json2.js later
  compileFunction : function(source, ddoc, name, sandbox) {
    if (!source) throw(["error","not_found","missing function"]);

    var functionObject = null;
    var sandbox = sandbox || create_sandbox();

    var require = function(name, module) {
      module = module || {};
      var newModule = resolveModule(name.split('/'), module.parent, ddoc);
      if (!ddoc._module_cache.hasOwnProperty(newModule.id)) {
        // create empty exports object before executing the module,
        // stops circular requires from filling the stack
        ddoc._module_cache[newModule.id] = {};
        var s = "(function (module, exports, require) { " + newModule.current + "\n });";
        try {
          var func = sandbox ? evalcx(s, sandbox, newModule.id) : eval(s);
          func.apply(sandbox, [newModule, newModule.exports, function(name) {
            return require(name, newModule);
          }]);
        } catch(e) {
          throw [
            "error",
            "compilation_error",
            "Module require('" +name+ "') raised error " + e.toSource()
          ];
        }
        ddoc._module_cache[newModule.id] = newModule.exports;
      }
      return ddoc._module_cache[newModule.id];
    };

    if (ddoc) {
      sandbox.require = require;
      if (!ddoc._module_cache) ddoc._module_cache = {};
    }

    try {
      if(typeof CoffeeScript === "undefined") {
        var rewrittenFun = rewriteFunInt(source);
        functionObject = evalcx(rewrittenFun, sandbox, name);
      } else {
        var transpiled = CoffeeScript.compile(source, {bare: true});
        functionObject = evalcx(transpiled, sandbox, name);
      }
    } catch (err) {
      throw([
        "error",
        "compilation_error",
        err.toSource() + " (" + source + ")"
      ]);
    };
    if (typeof(functionObject) == "function") {
      return functionObject;
    } else {
      throw(["error","compilation_error",
        "Expression does not eval to a function. (" + source.toString() + ")"]);
    };
  },
  recursivelySeal : function(obj) {
    seal(obj);
    for (var propname in obj) {
      if (typeof obj[propname] == "object") {
        arguments.callee(obj[propname]);
      }
    }
  }
};

// prints the object as JSON, and rescues and logs any JSON.stringify() related errors
function respond(obj) {
  try {
    print(JSON.stringify(obj));
  } catch(e) {
    log("Error converting object to JSON: " + e.toString());
    log("error on obj: "+ obj.toSource());
  }
};

function log(message) {
  // idea: query_server_config option for log level
  if (typeof message == "xml") {
    message = message.toXMLString();
  } else if (typeof message != "string") {
    message = JSON.stringify(message);
  }
  respond(["log", String(message)]);
};

function isArray(obj) {
  return toString.call(obj) === "[object Array]";
}
