/**
 * The API Handler handles all API http requests
 */

/*
 * 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
 *
 * 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 ERR = require("async-stacktrace");
var fs = require("fs");
var api = require("../db/API");
var padManager = require("../db/PadManager");
var randomString = require("../utils/randomstring");

//ensure we have an apikey
var apikey = null;
try
{
  apikey = fs.readFileSync("./APIKEY.txt","utf8");
}
catch(e)
{
  apikey = randomString(32);
  fs.writeFileSync("./APIKEY.txt",apikey,"utf8");
}

//a list of all functions
var version =
{ "1":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  }
, "1.1":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  , "listAllGroups"             : []
  }
, "1.2":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  , "listAllGroups"             : []
  , "checkToken"                : []
  }
, "1.2.1":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "listAllPads"               : []
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  , "listAllGroups"             : []
  , "checkToken"                : []
  }
, "1.2.7":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "listAllPads"               : []
  , "createDiffHTML"            : ["padID", "startRev", "endRev"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getRevisionsCount"         : ["padID"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  , "listAllGroups"             : []
  , "checkToken"                : []
  , "getChatHistory"            : ["padID"]
  , "getChatHistory"            : ["padID", "start", "end"]
  , "getChatHead"               : ["padID"]
  }
, "1.2.8":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "listAllPads"               : []
  , "createDiffHTML"            : ["padID", "startRev", "endRev"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getAttributePool"          : ["padID"]
  , "getRevisionsCount"         : ["padID"]
  , "getRevisionChangeset"      : ["padID", "rev"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  , "listAllGroups"             : []
  , "checkToken"                : []
  , "getChatHistory"            : ["padID"]
  , "getChatHistory"            : ["padID", "start", "end"]
  , "getChatHead"               : ["padID"]
  }
, "1.2.9":
  { "createGroup"               : []
  , "createGroupIfNotExistsFor" : ["groupMapper"]
  , "deleteGroup"               : ["groupID"]
  , "listPads"                  : ["groupID"]
  , "listAllPads"               : []
  , "createDiffHTML"            : ["padID", "startRev", "endRev"]
  , "createPad"                 : ["padID", "text"]
  , "createGroupPad"            : ["groupID", "padName", "text"]
  , "createAuthor"              : ["name"]
  , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
  , "listPadsOfAuthor"          : ["authorID"]
  , "createSession"             : ["groupID", "authorID", "validUntil"]
  , "deleteSession"             : ["sessionID"]
  , "getSessionInfo"            : ["sessionID"]
  , "listSessionsOfGroup"       : ["groupID"]
  , "listSessionsOfAuthor"      : ["authorID"]
  , "getText"                   : ["padID", "rev"]
  , "setText"                   : ["padID", "text"]
  , "getHTML"                   : ["padID", "rev"]
  , "setHTML"                   : ["padID", "html"]
  , "getAttributePool"          : ["padID"]
  , "getRevisionsCount"         : ["padID"]
  , "getRevisionChangeset"      : ["padID", "rev"]
  , "getLastEdited"             : ["padID"]
  , "deletePad"                 : ["padID"]
  , "copyPad"                   : ["sourceID", "destinationID", "force"]
  , "movePad"                   : ["sourceID", "destinationID", "force"]
  , "getReadOnlyID"             : ["padID"]
  , "setPublicStatus"           : ["padID", "publicStatus"]
  , "getPublicStatus"           : ["padID"]
  , "setPassword"               : ["padID", "password"]
  , "isPasswordProtected"       : ["padID"]
  , "listAuthorsOfPad"          : ["padID"]
  , "padUsersCount"             : ["padID"]
  , "getAuthorName"             : ["authorID"]
  , "padUsers"                  : ["padID"]
  , "sendClientsMessage"        : ["padID", "msg"]
  , "listAllGroups"             : []
  , "checkToken"                : []
  , "getChatHistory"            : ["padID"]
  , "getChatHistory"            : ["padID", "start", "end"]
  , "getChatHead"               : ["padID"]
  }
};

// set the latest available API version here
exports.latestApiVersion = '1.2.9';

// exports the versions so it can be used by the new Swagger endpoint
exports.version = version;

/**
 * Handles a HTTP API call
 * @param functionName the name of the called function
 * @param fields the params of the called function
 * @req express request object
 * @res express response object
 */
exports.handle = function(apiVersion, functionName, fields, req, res)
{
  //check if this is a valid apiversion
  var isKnownApiVersion = false;
  for(var knownApiVersion in version)
  {
    if(knownApiVersion == apiVersion)
    {
      isKnownApiVersion = true;
      break;
    }
  }

  //say goodbye if this is an unkown API version
  if(!isKnownApiVersion)
  {
    res.statusCode = 404;
    res.send({code: 3, message: "no such api version", data: null});
    return;
  }

  //check if this is a valid function name
  var isKnownFunctionname = false;
  for(var knownFunctionname in version[apiVersion])
  {
    if(knownFunctionname == functionName)
    {
      isKnownFunctionname = true;
      break;
    }
  }

  //say goodbye if this is a unkown function
  if(!isKnownFunctionname)
  {
    res.send({code: 3, message: "no such function", data: null});
    return;
  }

  //check the api key!
  fields["apikey"] = fields["apikey"] || fields["api_key"];

  if(fields["apikey"] != apikey.trim())
  {
    res.send({code: 4, message: "no or wrong API Key", data: null});
    return;
  }

  //sanitize any pad id's before continuing
  if(fields["padID"])
  {
    padManager.sanitizePadId(fields["padID"], function(padId)
    {
      fields["padID"] = padId;
      callAPI(apiVersion, functionName, fields, req, res);
    });
  }
  else if(fields["padName"])
  {
    padManager.sanitizePadId(fields["padName"], function(padId)
    {
      fields["padName"] = padId;
      callAPI(apiVersion, functionName, fields, req, res);
    });
  }
  else
  {
    callAPI(apiVersion, functionName, fields, req, res);
  }
}

//calls the api function
function callAPI(apiVersion, functionName, fields, req, res)
{
  //put the function parameters in an array
  var functionParams = version[apiVersion][functionName].map(function (field) {
    return fields[field]
  })

  //add a callback function to handle the response
  functionParams.push(function(err, data)
  {
    // no error happend, everything is fine
    if(err == null)
    {
      if(!data)
        data = null;

      res.send({code: 0, message: "ok", data: data});
    }
    // parameters were wrong and the api stopped execution, pass the error
    else if(err.name == "apierror")
    {
      res.send({code: 1, message: err.message, data: null});
    }
    //an unkown error happend
    else
    {
      res.send({code: 2, message: "internal error", data: null});
      ERR(err);
    }
  });

  //call the api function
  api[functionName].apply(this, functionParams);
}
