
function MurrixDb(url, user_id)
{
  /* Class variable declaration */
  
  var parent_   = this;
  this.url_     = url;
  this.user_id_ = user_id;

  /* Public methods */
 
  /**
   * Login a user.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data      - Node data JSON object for the new user.
   *  
   * 
   * @param username  - Username of user to login.
   * @param password  - Password of user to login.
   * @param callback  - Result callback function.
   *  
   * @return          - Transaction ID.
   * @throws          - MURRIX_RESULT_CODE
   */
  this.Login = function(username, password, callback)
  {
    if (!username || !password || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("Login", { "Username" : username, "Password" : SHA1(password) }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["Node"]);
    });
  }
  
  /**
   * Logout and go to default user.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data      - Node data JSON object for the new user.
   *  
   * 
   * @param callback  - Result callback function.
   *  
   * @return          - Transaction ID.
   * @throws          - MURRIX_RESULT_CODE
   */
  this.Logout = function(callback)
  {
    if (!callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("Logout", { }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["Node"]);
    });
  }
 
  /**
   * Create a new node.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data      - Node data JSON object of the created node.
   *  
   * 
   * @param node_data - Node data JSON object, should not have a valid id.
   * @param callback  - Result callback function.
   *  
   * @return          - Transaction ID.
   * @throws          - MURRIX_RESULT_CODE
   */
  this.CreateNode = function(node_data, callback)
  {
    if (!node_data || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("CreateNode", { "Node" : node_data }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["Node"]);
    });
  }
  
  /**
   * Update an existing node.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data      - Node data JSON object of the updated node.
   *  
   * 
   * @param node_data - Node data JSON object, must have a valid id.
   * @param callback  - Result callback function.
   *  
   * @return          - Transaction ID.
   */
  this.UpdateNode = function(node_data, callback)
  {
    if (!node_data || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("UpdateNode", { "Node" : node_data }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["Node"]);
    });
  }
  
  /**
   * Delete an existing node.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data      - Node data JSON object the deleted node.
   *  
   * 
   * @param node_id   - Node data JSON object.
   * @param callback  - Result callback function.
   *  
   * @return          - Transaction ID.
   */
  this.DeleteNode = function(node_id, callback)
  {
    if (!node_id || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("DeleteNode", { "NodeId" : node_id }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["Node"]);
    });
  }
  
  /**
   * Link two nodes together.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data_up, JSON data_down, string role)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data_up   - Node data JSON object for top node.
   *   param node_data_down - Node data JSON object for bottom node.
   *   param role           - Role relationship between nodes.
   *  
   * 
   * @param node_id_up    - Node data JSON object for top most node.
   * @param node_id_down  - Node data JSON object for bottom most node.
   * @param role          - Role relationship between nodes.
   * @param callback      - Result callback function.
   *  
   * @return           - Transaction ID.
   */
  this.LinkNodes = function(node_id_up, node_id_down, role, callback)
  {
    if (!node_id_up || !node_id_down || !role || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("LinkNodes", { "NodeIdUp" : node_id_up, "NodeIdDown" : node_id_down, "Role" : role }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["NodeUp"], response_data["NodeDown"], response_data["Role"]);
    });
  }
  
  /**
   * Unlink two nodes from eachother.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON data_up, JSON data_down, string role)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data_up   - Node data JSON object for top node.
   *   param node_data_down - Node data JSON object for bottom node.
   *   param role           - Role relationship between nodes.
   *  
   * 
   * @param node_id_up    - Node data JSON object for top most node.
   * @param node_id_down  - Node data JSON object for bottom most node.
   * @param role          - Role relationship between nodes.
   * @param callback      - Result callback function.
   *  
   * @return           - Transaction ID.
   */
  this.UnlinkNodes = function(node_id_up, node_id_down, role, callback)
  {
    if (!node_id_up || !node_id_down || !role || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("UnlinkNodes", { "NodeIdUp" : node_id_up, "NodeIdDown" : node_id_down, "Role" : role }, function(transaction_id, result_code, response_data)
    {
      callback(transaction_id, result_code, response_data["NodeUp"], response_data["NodeDown"], response_data["Role"]);
    });
  }
  
  /**
   * Search for nodes based on a query object.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, int[] id_list)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_list      - List of nodes matching the query.
   *  
   * 
   * @param query      - Data JSON object with query data.
   * @param callback   - Result callback function.
   *  
   * @return           - Transaction ID.
   */
  this.SearchNodes = function(query, callback)
  {
    var self = this;
    
    this.SearchNodeIds(query, function(transaction_id, result_code, node_id_list)
    {
      // TODO: Check result
      
      self.FetchNodes(node_id_list, callback);
    });
  }
  
  /**
   * Search for node ids based on a query object.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, int[] id_list)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_id_list   - List of node IDs matching the query.
   *  
   * 
   * @param query      - Data JSON object with query data.
   * @param callback   - Result callback function.
   *  
   * @return           - Transaction ID.
   */
  this.SearchNodeIds = function(query, callback)
  {
    if (!query || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("SearchNodeIds", { "Query" : query }, function(transaction_id, result_code, response_data)
    {
      var node_id_list = response_data["NodeIdList"] ? response_data["NodeIdList"] : [];
      
      callback(transaction_id, result_code, node_id_list);
    });
  }
  
  
  /**
   * Get nodes identified by node ID list.
   * 
   * Callback(int transaction_id, MURRIX_RESULT_CODE result, JSON[] data_list)
   *   param transaction_id - Transaction ID.
   *   param result_code    - MURRIX_RESULT_CODE_OK on success.
   *   param node_data_list - List of JSON node objects.
   *  
   * 
   * @param node_id_list    - List of Node IDs.
   * @param callback   - Result callback function.
   *  
   * @return           - Transaction ID.
   */
  this.FetchNodes = function(node_id_list, callback)
  {
    if (!node_id_list || !callback)
    {
      throw MURRIX_RESULT_CODE_PARAM;
    }
    
    return parent_.CallServer("FetchNodes", { "NodeIdList" : node_id_list }, function(transaction_id, result_code, response_data)
    {
      var node_data_list = response_data["NodeList"] ? response_data["NodeList"] : {};
      
      callback(transaction_id, result_code, node_data_list);
    });
  }
  
  
  this.CallServer = function(action, data, callback)
  {
    var transaction_id  = jQuery.now();
    var url             = parent_.url_ + "?Action=" + action + "&TransactionId=" + transaction_id;
    var request_args    = { "CurrentUserId" : parent_.user_id_, "Data" : data };
    
    
    /* Post request to server */
    jQuery.post(url, request_args, function(response_args, text_status)
    {
      /* Check that the request succeeded */
      if ("success" != text_status)
      {
        callback(transaction_id, MURRIX_RESULT_CODE_REQUEST_FAILED, null);
        return;
      }
      

      /* Check that the request action was performed successfully and update current user id */
      if (MURRIX_RESULT_CODE_OK == response_args["ResultCode"])
      {
         /* Update the current user */
        parent_.user_id_ = parseInt(response_args["CurrentUserId"]);
        // TODO: Should we have some sort of event for this?
      }
      
      
      /* Return data to the caller */
      callback(transaction_id, response_args["ResultCode"], response_args["Data"]);
      
    }, "json");
    
    
    /* Return transaction id to caller */
    return transaction_id;
  }
} 

