/*
  rdfapi-js 0.1 - RDF API for JavaScript
	Copyright (C) 2008 Martin Peklo and Sebastian Dietzold
  http://aksw.org/Projects/RDFAPI-JS/

  $Id: Model.js 2649 2008-12-09 09:51:27Z martinpeklo $

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
(function(){
/*
 * CONFIG
*/
if (typeof(RAJ) == 'undefined') {
  RAJ = new Object();
}

// validating mode, checks every model prior to usage
RAJ.validating = true;

//linesPerPager, defines the standard number of triples per page
RAJ.linesPerPage = 15;

//defines the number of Characters eval() will parse at once
RAJ.parseBlockSize = 500000;

RAJ.debug=true;

//defines the Path to rdfa.js
__RDFA_BASE='./'

// TODO: Should we provide methods like registerCallback(trigger, function) or a similar one?
//Callback Function for deleting/editing
if (typeof(RAJ.CALLBACK_DONE_EDITING) == "undefined") RAJ.CALLBACK_DONE_EDITING = function() {};
if (typeof(RAJ.CALLBACK_DONE_PARSING) == "undefined") RAJ.CALLBACK_DONE_PARSING = function() {};


RAJ.modelList = new Array();
RAJ.currentPage = 1;
RAJ.currentModel = new Object();
RAJ.modelCount = 0;
RAJ.tempTripleStore = new Array();
RAJ.tempTripleStore[0] = new Object();
RAJ.tempTripleStore[1] = new String();

    if ((!RAJ.debug)||(!window.log)) window.log = {
        toggle: function() {},
        move: function() {},
        resize: function() {},
        clear: function() {},
        debug: function() {},
        info: function() {},
        warn: function() {},
        error: function() {},
        profile: function() {}
    };

    if ((window.console)&&(RAJ.debug)) {console.log("Press F2 to view Debug and Error Messages.")}

/**
 * Creates a new Model.
 *
 * <p>This constructor method for models uses a key/value pair object as a
 * parameter to specifiy from where it should take the initial statements.
 * The method uses the corresponding parser to create a new instance from the
 * given initial triples.</p>
 *
 * <p>The following keys are used in the key/value parameter:</p>
 * <ul>
 * <li>url: The initial source triples as a gettable resource locator.</li>
 * <li>string: The initial source triples as a parseable string.</li>
 * <li>type: The type of source to parse. The value is one of the following IDs:
 *   <ul>
 *       <li>rdfa - An RDFa enhanced XHTML page.
 *              (currently only the current DOM document, which means
 *              string and url is empty)</li>
 *       <li>xml  - An RDF/XML document.
 *              (currently only URLs supported, no string data)</li>
 *       <li>json - And RDF/JSON document.
 *              (currently only string data supported, no URLs)</li>
 *   </ul>
 *   If you do not give a type key in the options parameter, RAJ tries to use
 *   the given object as a JSON representated model.
 *</li></ul>
 *
 * Notes:
 * <ul>
 * <li>If both url and string are given, string data is preferred over urls.</li>
 * <li>If no url and string is given, we try to use the local document.</li>
 * <li>If only an URL is given the type RDF/XML is assumed.</li>
 * <li>If only a string is given, the type JSON is assumed. In this case you
 *     can put in the string directly, e.g. <code>var myModel = Model('...').</code></li>
 *</ul>
 *
 * @class Represents a model.
 * @param options Key/value pairs to initialize the model (optional)
 * @return an instance of Model
 * @example var myModel = Model({
 *   type: "xml",
 *   url: "http://sebastian.dietzold.de/rdf/foaf.rdf"
 *   }) // use an XML/RDF document
 * @example var myModel = Model( {type: "rdfa"} ) // use current RDFa document
 * @example var myModel = Model(" {...} ") // use an json string
 */
Model = function (options) {


 /// <name>loadit(uri)</name>
/// <summary>loads the JSONobject from uri into a Model</summary>
function pLoadJson(uri) {
	RAJ.CALLBACK_DONE_PARSING=function(){window.log.debug("calling back");RAJ.CALLBACK_DONE_EDITING()};
    window.log.debug("loading jsonUrl  "+uri);
    var out = $.ajax({url: uri, async: false}).responseText;
	return pParseJson(out)
}

 /**
  * loads the JSONobject from a string out into a Model
  * @private
  * TODO parseJSON should be private --> needs complete rewrite for doing that
  */
        function pParseJson(jsonString) {
            /*var ol = jsonString.length;
            var pCount = 0;
            var done=false;
            var a = 0;
            var partialModels=0;
            var temp;
            var parsedObject;
            jsonString=jsonString.replace(/\n/g,"");
            while (done===false) {
                if (jsonString.substr(a,1)==='{') {
                    pCount++;
                }
                if (jsonString.substr(a,1)==='}') {
                    pCount--;
                }
                if ((jsonString.substr(a,1)==='}')&&(pCount===1)&&(a>RAJ.parseBlockSize)) {
                    temp = (jsonString.substr(0,a+1)+"}");
                    temp = eval("("+temp+")");
                    new MODEL(temp,"jsonObject");
                    jsonString = (jsonString.substring(a+1));
                    jsonString=jsonString.replace(/,/,"{");
                    pCount=0;
                    partialModels++;
                    a=-1;
                }
                if (jsonString.length<=RAJ.parseBlockSize) {
                    temp = eval("("+jsonString+")");
                    new Model(temp,"jsonObject");
                    partialModels++;
                    var all = RAJ.modelCount;
                    for (var x=1;x<partialModels;x++) {
                        RAJ.modelList[all-partialModels].add(RAJ.modelList[all-x]);
                        RAJ.modelList.splice([all-x],1);
                        RAJ.modelCount--;
                    }
                    done=true;
                }
                a++
            }
            RAJ.currentModel=RAJ.modelList[RAJ.modelList.length-1];
            RAJ.currentPage=1;
            RAJ.CALLBACK_DONE_EDITING();
            return RAJ.currentModel.jsonObject
           */
         //alert("Parsing   "+jsonString);
         jsonString=jsonString.replace(/\n/g,"");
         //this.jsonObject=JSON.parse(jsonString);
         //alert(this.jsonObject.toSource());
         //RAJ.CALLBACK_DONE_EDITING();
         return JSON.parse(jsonString)
        }

function pLoadXml(uri) {
$.Talis.Convert(uri, function(json) {this.jsonObject=pParseJson(json.toSource());});
}

function pLoadRdfa(uri) {
    RAJ.CALLBACK_DONE_PARSING=function(){window.log.debug("calling back");RAJ.CALLBACK_DONE_EDITING()}
	window.log.debug("pLoadRdfa "+uri);
    if (!document.getElementById("rdfaDiv")) {
		div=document.createElement("div");
		div.id="rdfaDiv";
		div.style.display="none";
		document.body.appendChild(div);
		}
	$("#rdfaDiv").load(uri, function() {
										RDFA.CALLBACK_DONE_PARSING = function() {pParseRdfa();};
										RDFA.parse();
										});
}

/// <name>parseRDFa()</name>
/// <summary>parses the current Model in RDFA.triplestore into a new Model</summary>
// // TODO parseRDFa should be private --> moved to Testapi, cause it needs RDFA.js ????
function pParseRdfa() {
 window.log.debug("pParseRdfa");
  var temp=new Object();
  var subject,predicate,object,tempObject;
  //window.log.debug(RDFA.triplestore.statements.length);
  for (var a=0; a<RDFA.triplestore.statements.length; a++) {
    //window.log.debug(RDFA.triplestore.statements[a].subject.uri);
    subject=RDFA.triplestore.statements[a].subject.uri;
    if (!temp[subject]) {
      temp[subject]=new Object();
      for (var b=0; b<RDFA.triplestore.statements.length; b++) {
        //window.log.debug(RDFA.triplestore.statements[b].predicate.uri);
        predicate=RDFA.triplestore.statements[b].predicate.uri;
        //window.log.debug(subject+RDFA.triplestore.statements[b].subject.uri)
        if ((subject==RDFA.triplestore.statements[b].subject.uri)&&(!temp[subject][predicate])) {
          temp[subject][predicate]=new Array();
          for (var c=0; c<RDFA.triplestore.statements.length; c++) {
            if ((subject==RDFA.triplestore.statements[c].subject.uri)&&(predicate==RDFA.triplestore.statements[c].predicate.uri)) {
              tempObject=new Object();
              if (RDFA.triplestore.statements[c].object.uri) tempObject.type="uri";
              if (RDFA.triplestore.statements[c].object.value) tempObject.type="literal";
              if (RDFA.triplestore.statements[c].object.uri)tempObject.value=RDFA.triplestore.statements[c].object.uri;
              if (RDFA.triplestore.statements[c].object.value)tempObject.value=RDFA.triplestore.statements[c].object.value;
              if (RDFA.triplestore.statements[c].why.lang) tempObject.lang=RDFA.triplestore.statements[c].why.lang;
              if (RDFA.triplestore.statements[c].why.datatype) tempObject.datatype=RDFA.triplestore.statements[c].why.datatype;
              temp[subject][predicate].push(tempObject);
            }
          }
        }
      }
    }
  }
  //RAJ.currentModel=new Model(temp);
  //RAJ.currentPage=1;
  //RAJ.currentModel.rdfaEnabled=true;
  //RAJ.CALLBACK_DONE_EDITING();
  RDFA.CALLBACK_DONE_PARSING = function() {};
  RAJ.currentModel.jsonObject=temp;
  return temp
}
  /**
  * merges the statements of two MODELs
  * @private
  */
  function pMergeModels(origin,what) {
    var tempObject;
    if (typeof(what) != "object") {
      return false;
    }
    for (var subject in what) {
      if (!origin[subject]) {
        origin[subject] = new Object()
      }
      for (var predicate in what[subject]) {
        if (!origin[subject][predicate]) {
          origin[subject][predicate] = new Array();
        }
        for (var i=0; i<what[subject][predicate].length; i++) {
          var test = pArraySearch(what[subject][predicate][i], origin[subject][predicate]);
          if (test==-1) {
            tempObject = new Object;
            for (var object in what[subject][predicate][i]) {
              tempObject[object]=what[subject][predicate][i][object];
            }
            origin[subject][predicate].push(tempObject);
          }

        }

      }
    }
		
    return origin;
  }

  /**
  * removes statements from a model
  * @param model all statements which has to be deleted
  * @return TRUE on success, otherwise FALSE
  */
  this.remove = function (model) {
    this.jsonObject=pRemoveStatements(this.jsonObject, model.jsonObject);
  };

  /**
  * removes all triples contained in MODEL2 from MODEL1
  * @private
  */
  function pRemoveStatements(origin, what) {
    if (typeof(what) != "object") return false;
    for (var subject in what) {
      var save=false;
      for (var predicate in what[subject]) {
        for (var i=0; i<what[subject][predicate].length; i++) {
          var a = pArraySearch(what[subject][predicate][i], origin[subject][predicate])
          if (a>-1) {
            origin[subject][predicate].splice(a,1);
          }
        }
        save=false;
        for (a in origin[subject][predicate]) {
          save=true;break;
        }
        if (!save) {
          delete origin[subject][predicate];
        }
      }
      save=false;
      for (a in origin[subject]) {
        save=true;break;
      }
      if (!save) {
        delete origin[subject];
      }
    }
    return origin;
  }

 
  /**
  * returns true if origin contains all triples from what
  * @private
  */
  function pContainsStatements(origin,what) {
    if (typeof(what) != "object") {
      return false;
    }
    var test= true;
    for (var subject in what) {
      if (origin[subject]) for (var predicate in what[subject]) {
        for (var i=0; i<what[subject][predicate].length; i++) {
          var a = pArraySearch(what[subject][predicate][i], origin[subject][predicate]);
          if (a==-1) {
            test=false;
            break;
          }
        }

      } else {
        test=false;
      }
    }
    return test;

  }

  /**
  * searches the Array haystack for the object needle
  * @param needle
  * @param haystack
  * @return elementindexnumber or -1 if not found
  * @private
  */
  function pArraySearch(needle, haystack) {
    if (typeof(haystack) != "object") {
      alert("haystack no object"); return -1;
    }
    if (!(haystack.length)) {
      return -1;
    }
    if (!(typeof(needle) == "object")) {
      alert("needle no object"); return -1;
    }
    if (!(needle.value)) {
      alert("needle no value"); return -1;
    }
    for (var i=0; i<haystack.length; i++) {
      var test=false;
      for (var a in needle) {
        if (haystack[i][a]) {
          if ((needle[a])!=(haystack[i][a])) {
            test=false;break;
          }
          else {
            test= true;
          }
        }
      }
      if(test) {
        return i;
      }

    }
    return -1;
  }

  /**
  * pFindObjectIndex
  * @private
  * TODO: pFindObjectIndex should be part of find() ---> still needs thinking
  */
  this.findObjectIndex=function (subject,predicate,object) {
    return pArraySearch(object,this.jsonObject[subject][predicate]);
  }

/*
 *this.pFindObjectIndex=function (subject,predicate,object) {
    return pArraySearch(object,this.jsonObject[subject][predicate]);
  }
  */

  // TODO: toSource should be wrapped for usage in Webkit

 /**
  * check the jsonObject for validity
  * @param jsonObject the model
  * @private
  */
  function pCheckModel(jsonObject) {
    if (jsonObject) {
      if (typeof(jsonObject) != "object") {
        window.log.error(jsonObject.toSource()+" is not an object");return false;
      }
      for (var subject in jsonObject) {
        if (typeof(jsonObject[subject])!="object") {
          window.log.error(jsonObject[subject].toSource()+" is no valid subject");return false;
        }
        if (jsonObject[subject].length) {
          window.log.error(jsonObject[subject].toSource()+" is no valid subject, maybe an Array?");return false;
        }
        for (var predicate in jsonObject[subject]) {
          if (typeof(jsonObject[subject][predicate])!="object") {
            window.log.error(jsonObject[subject][predicate].toSource()+" should be predicate, but is not an object");return false;
          }
          if (!jsonObject[subject][predicate].length) {
            window.log.error("[predicate] hat keine länge");return false;
          }
          for (var i=0; i<jsonObject[subject][predicate].length; i++) {
            if (typeof(jsonObject[subject][predicate][i])!="object") {
              window.log.error(jsonObject[subject][predicate][i].toSource()+"should be the object, but is not an object");return false;
            }
            if (!jsonObject[subject][predicate].length) {
              window.log.error(jsonObject[subject][predicate].toSource()+" should contain objects, but is no array");return false;
            }
            if (typeof(jsonObject[subject][predicate][i].value)!="string") {
              window.log.error(jsonObject[subject][predicate][i].value+"sould be a string");return false;
            }
            if (!(jsonObject[subject][predicate][i].type)==(("literal")||("bnode")||("uri"))) {
              window.log.error(jsonObject[subject][predicate][i].type+" is an invalid type");return false;
            }
          }
        }
      }
    }
    return true;
  }

  function pFind (subject, predicate, object, params) {
    window.log.debug(subject);
    var out=new Object;
    var outTemp=new Object;
    var tempString;
    if (typeof(subject)=="string") {
      tempString=subject;subject = new Object;subject.value=tempString;subject.type="uri";
    }
    if (typeof(predicate)=="string") {
      tempString=predicate;predicate = new Object;predicate.value=tempString;predicate.type="uri";
    }
    if (typeof(object)=="string") {
      tempString=object;object = new Object;object.value=tempString;object.type="literal";
    }
    window.log.debug("finding subject: "+subject.type+subject.value);
    for (var subj in RAJ.currentModel.jsonObject) {
      if ((( ((subject.RegExp==true)&&(subj.search(subject.value)>-1)) || ((subject.RegExp==false)&&(subject.value==subj)) )&&(subject.type=="uri")&&(subj.indexOf("_:")!=0))||((!subject.value)&&(subject.type=="uri")&&(subj.indexOf("_:")!=0)) || ((subject.type=="bnode")&&(subj.indexOf("_:")==0))) {
        window.log.debug(subj+" passed the test");
        window.log.debug("finding predicate: "+predicate.type+predicate.value);
        for (var predi in RAJ.currentModel.jsonObject[subj]) {
          if (( ((predicate.RegExp==true)&&(predi.search(predicate.value)>-1)) || ((predicate.RegExp==false)&&(predicate.value==predi)) )||(!predicate.value)) {
            window.log.debug(predi+" passed the test");
            for (var i=0; i<RAJ.currentModel.jsonObject[subj][predi].length; i++) {
              if ( ((object.RegExp==true)&&(RAJ.currentModel.jsonObject[subj][predi][i].value.search(object.value)>-1)) || ((object.RegExp==false)&&(object.value==RAJ.currentModel.jsonObject[subj][predi][i].value)) ||(!object.value)) {
                if ((object.type==RAJ.currentModel.jsonObject[subj][predi][i].type)||(!object.type)) {
                  if ((object.lang==RAJ.currentModel.jsonObject[subj][predi][i].lang)||(!object.lang)) {
                    if ((object.datatype==RAJ.currentModel.jsonObject[subj][predi][i].datatype)||(!object.datatype)) {
                      if (!out[subj]) out[subj]=new Object();
                      if (!out[subj][predi]) out[subj][predi]=new Array();
                      if (RAJ.currentModel.jsonObject[subj][predi][i].value) outTemp.value=RAJ.currentModel.jsonObject[subj][predi][i].value;
                      if (RAJ.currentModel.jsonObject[subj][predi][i].type) outTemp.type=RAJ.currentModel.jsonObject[subj][predi][i].type;
                      if (RAJ.currentModel.jsonObject[subj][predi][i].lang) outTemp.lang=RAJ.currentModel.jsonObject[subj][predi][i].lang;
                      if (RAJ.currentModel.jsonObject[subj][predi][i].datatype) outTemp.datatype=RAJ.currentModel.jsonObject[subj][predi][i].datatype;
                      out[subj][predi][out[subj][predi].length]=outTemp;
                      //window.log.debug(out.toSource());
                      //window.log.debug("Pushed: "+outTemp.toSource());
                      delete(outTemp); outTemp=new Object();
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
    window.log.debug("OUT: "+out.toSource());
    return out;
  }

  /// <name>Model.exchangeStatement(oldTriple,newTriple)</name>
  /// <summary>removes oldTriple and replaces it by newTriple if not "none"</summary>
  // TODO: exchangeStatement should be redesigned
  this.pExchangeStatement = function (triple,newSubject,newPredicate,newObject) {
    if (!pContainsStatements(this.jsonObject,triple)==1) {
      alert(triple.toSource()+" not in "+this.jsonObject.toSource()); return false
      }
    var tempObject=new Object();
    tempObject[newSubject]=new Object();
    tempObject[newSubject][newPredicate]=new Array();
    tempObject[newSubject][newPredicate][0]=new Object();
    tempObject[newSubject][newPredicate][0].value=newObject;
    for (var a in triple) {
      for (var b in triple[a]) {
        if (triple[a][b][0].type) tempObject[newSubject][newPredicate][0].type=triple[a][b][0].type;
        if (triple[a][b][0].datatype) tempObject[newSubject][newPredicate][0].datatype=triple[a][b][0].datatype;
        if (triple[a][b][0].lang) tempObject[newSubject][newPredicate][0].lang=triple[a][b][0].lang;
      }
    }
    //window.log.debug("Editing"+triple.toSource()+"  TO  "+tempObject.toSource());
    pRemoveStatements(this.jsonObject,triple);
    pMergeModels(this.jsonObject,tempObject)
    RAJ.CALLBACK_DONE_EDITING();
    return true;
  }

  /// <name>Model.removeStatementsRDFa(triple)</name>
  /// <summary>removes triple from Memory Model and RDFa Data contained in the document</summary>
  // TODO: removeStatementsRDFa should be deleted or private
  function pRemoveStatementsRDFa(triple) {
    if (!pContainsStatements(this.jsonObject,triple)==1) {
      alert(triple.toSource()+" not in "+this.jsonObject.toSource()); return false
      }
    pRemoveStatements(this.jsonObject,triple);
    RAJ.tempTripleStore[0]=triple;
    // a function that is called on an element when a triple pertains to it
    // with the element being the literal object
    var temp=new Array();
    if (RDFA) RDFA.CALLBACK_NEW_TRIPLE_WITH_LITERAL_OBJECT = function(el, triple) {
      if (triple) {
        if (RAJ.tempTripleStore[0][triple.subject.uri])
          if (RAJ.tempTripleStore[0][triple.subject.uri][triple.predicate.uri])
            if (RAJ.tempTripleStore[0][triple.subject.uri][triple.predicate.uri][0].value==triple.object.value)
            {
              window.log.debug(RAJ.tempTripleStore[0].toSource()+"deleted")
              el.innerHTML="";
            }
      }
    }

    // a function that is called on an element when a triple pertains to it
    // with the element being the clickable link for a URI object
    if (RDFA) RDFA.CALLBACK_NEW_TRIPLE_WITH_URI_OBJECT = function(el, triple) {
      if (triple) {
        if (RAJ.tempTripleStore[0][triple.subject.uri])
          if (RAJ.tempTripleStore[0][triple.subject.uri][triple.predicate.uri])
            if (RAJ.tempTripleStore[0][triple.subject.uri][triple.predicate.uri][0].uri==triple.object.value)
            {
              window.log.debug(RAJ.tempTripleStore[0].toSource()+"deleted")
              el.innerHTML="";
            }
      }
    }

    // a function that is called on an element when a triple pertains to it
    // with the element being the subject of the assertions
    if (RDFA) RDFA.CALLBACK_NEW_TRIPLE_WITH_SUBJECT = function(el, triple) {
      if (triple) {
        if (RAJ.tempTripleStore[0][triple.subject.uri])
          if (RAJ.tempTripleStore[0][triple.subject.uri][triple.predicate.uri])
            if (RAJ.tempTripleStore[0][triple.subject.uri][triple.predicate.uri][0].value==triple.object.value)
            {
              window.log.debug(RAJ.tempTripleStore[0].toSource()+"deleted")
              el.innerHTML="";
            }
      }
    }
    if (RDFA) RDFA.parse();
    RDFA.reset();
    RAJ.CALLBACK_DONE_EDITING();
    return true;
  }

  /**
 * Updates Statements of a Model.
 *
 * <p>This method for models uses multiple key/value pairs in an object as a
 * parameter to specifiy which Statements will be modified, and with wich
 * Statements should these be replaced.</p>
 *
 * <p>The following keys are used in the key/value parameter:</p>
 * <ul>
 * <li>olds: The Statements to be modified as a JSON Object. If you do not use this key,
 * all new statements will just be added.</li>
 * <li>news: The Statement that replaces old. If you do not use this key, all old statements
 * will simply be deleted</li>
 * <li>rdfa: Set rdfa to TRUE if you want to perform a update action with respect to a
 * corresponding RDFa enhanced XHTML page, e.g. to change the Literal value of a statement
 * and you also want to change the value in the XHTML page.</li>
 * </ul>
 *
 * Notes:
 * <ul>
 * <li>The RDFa modus is very limited at the moment.</li>
 * </ul>
 *
 * @param options Key/value pairs to specify the Statements
 * @return TRUE if any Statements have been modified
 * @example var myModel.update({
 *   old: "",
 *   new: ""
 *   }) // to change one Statement
 * @example myModel.update( {type: "rdfa"} ) // to change one Statement incuding RDFA Data
 * @example myModel.update(" {...} ") // to Delete multiple Statements
 */
  this.update = function (options) {
    if ((options.rdfa==true)&&(options.olds)&&(!options.news)) {
        if (this.pRemoveStatementsRDFa(options.olds)) return true
    }

    if ((!options.rdfa)&&(options.olds)&&(!options.news)) {
        pRemoveStatements(this.jsonObject,options.olds);
        RAJ.CALLBACK_DONE_EDITING();
        return true
    }

    if ((!options.rdfa)&&(options.olds)&&(options.news)) {
        for (var a in options.news) {
            var newSubject=a;
            for (var b in options.news[a]) {
                var newPredicate=b;
                var newObject=options.news[a][b];
                this.pExchangeStatement(options.olds,newSubject,newPredicate,newObject);
            }

        }
    }
  }



  /**
  * Counts the statements of a mode
  * @return Number of statements contained in the model
  */
  this.count = function (subject,predicate,object) {
    var countingObject;
    if ((subject)||(predicate)||(object)) {
           alert("parameter count")
           countingObject=this.find(subject,predicate,object);
    }
    else countingObject=this.jsonObject;


    var count=0;
    for (var subj in countingObject) {
      for (var predi in countingObject[subj]) {
        for (var i=0; i<countingObject[subj][predi].length; i++) {
          if (countingObject[subj][predi][i].value) count++;
        }
      }
    }
    return count;
  };
	
 /**
  * checks if the model contains another model
  * @param model model which has to be inside
  * @return TRUE if all triples are contained, otherwise FALSE
  */
  this.contains = function (model) {
    return pContainsStatements(this.jsonObject, model.jsonObject);
  };

  /**
  * compares the model with another model
  * @param model which has to compared with
  * @return TRUE if models are equal, otherwise FALSE
  */
  this.compare = function (model) {
    if (!pContainsStatements(this.jsonObject, model.jsonObject)) {
      return false;
    }
    return pContainsStatements(model.jsonObject, this.jsonObject);
  };


/**
  * Adds a namespace declaration to the model
  * @param prefix the namespace prefix (string)
  * @param uri the namespace U/IRI (string)
  * @return TRUE on success, otherwise FALSE
  */
  this.addNamespace = function (prefix, uri) {
    var index = this.Namespaces.length;
    var temp = new Array;
    var exists = false;
    prefix = prefix+":";
    temp[0] = prefix;
    temp[1] = uri;

    for (var a=0;a<index;a++) {
      if (temp[0]==this.Namespaces[a][0]) exists=true;
    }
    if (!exists) this.Namespaces[index] = temp;
    if (!exists) return true
    else return false
}
	
  /**
  * provides a list of all namespace declarations
  * @return an Array of namespaces like {"prefix1": "uri1", "prefix2": "uri2"}
  */
  this.getNamespaces = function () {
      return this.Namespaces;
  }

/**
  * Finds all statements according to a SPO filter setup.
  * These SPO filter consist of three parts: subject, predicate and object.
  * Every part can be either a json-object or a string.
  *
  * Notes
  * <ul>
  * <li>According to the Resource Description Framework (RDF),
  * statement-subjects can be resources or bnodes, statement-predicates can be
  * resources only and statement-object can be resources, bnodes and
  * literals.</li>
  * <li>All parameters can be strings instead of json-objects. If used so,
  * strings for subjects and predicates are asumed as URIs, strings objects are
  * assumed as untyped literal without language.</li>
  * <li>If these objects have a string-Parameter RegExp="true" the values are
  * asumed as regular expressions (TODO: this must be documented in the
  * examples too).</li>
  * </ul>
  * 
  * @param subject json-object or string which represents the subject resource
  * or bnode. A string is interpreted as an URI. Examples for this parameter:
  * <ul>
  * <li>A full URI: <code>{"value" : "http://example.com", "type" : "uri"}</code></li>
  * <li>A namespaced URI aka qname <code>{"value" : "foaf:name", "type" : "qname"}</code></li>
  * <li>A full URI as string: <code>"http://example.com"</code></li>
  * <li>A named bnode: <code>{"value" : "_:b1293", "type" : "bnode"}</code></li>
  * <li>An unnamed bnode: <code>{"type" : "bnode"}</code></li>
  * </ul>
  * 
  * @param predicate json-object or string which represents the predicate
  * resource. A string is interpreted as an URI. Examples for this parameter:
  * <ul>
  * <li>A full URI: <code>{"value" : "http://example.com", "type" : "uri"}</code></li>
  * <li>A namespaced URI aka qname <code>{"value" : "foaf:name", "type" : "qname"}</code></li>
  * <li>A full URI as string: <code>"http://example.com"</code></li>
  * </ul>
  *
  * @param object json-object or string which represents the object resource,
  * bnode or literal. A string is interpreted as Literal. Examples for this
  * parameter:
  * <ul>
  * <li>An untyped Literal without language: <code>{"value" : "2006", "type" : "literal"}</code></li>
  * <li>An untyped Literal but with language: <code>{"value" : "2006", "type" : "literal", lang: "de"}</code></li>
  * <li>A Literal with datatype: <code>{"value" : "2006", "type" : "literal", datatype: "...."}</code></li>
  * <li>A full URI: <code>{"value" : "http://example.com", "type" : "uri"}</code></li>
  * <li>A namespaced URI aka qname <code>{"value" : "foaf:name", "type" : "qname"}</code></li>
  * <li>A full URI as string: <code>"http://example.com"</code></li>
  * <li>A named bnode: <code>{"value" : "_:b1293", "type" : "bnode"}</code></li>
  * <li>An unnamed bnode: <code>{"type" : "bnode"}</code></li>
  * </ul>
  *
  * @param params a key/value pair object for special options (TODO: put here the index parameter)
  *
  * @return a model which contains all filtered statements or FALSE on error.
  * TODO: find functions seems to be a testfw candidate
  */
  this.find = function (subject, predicate, object, params) {
      var temp=pFind(subject, predicate, object, params);
      window.log.debug("temp"+temp)
      new Model(temp);
      return temp;
  }

	
  /**
  * Adds a statement or a model to the model
  * @param model model / statement object to add to the model
  * @return TRUE on success, otherwise FALSE
  */
  this.add = function (model) {
    //var a;var b;var temp = new Array;
    if (pMergeModels(this.jsonObject, model.jsonObject)!=false) return true
    else return false
  /*
		if (addObject.Namespaces.length>0) for (a=0;a<addObject.Namespaces.length;a++) {
			if (1) {
				alert(a+this.Namespaces.length);
				temp[0] = addObject.Namespaces[a][0];
				temp[1] = addObject.Namespaces[a][1];
				this.Namespaces.push(temp);
			}
		}
		*/
  };
 
  /**
  * checks the model for validity
  * @return TRUE on success, otherwise FALSE
  */
  this.check = function () {
    return pCheckModel(this.jsonObject);
  }



  RAJ.modelList[RAJ.modelCount] = this;
  RAJ.currentModel=this;
  this.Namespaces = new Array();
  this.storagePlace = RAJ.modelCount;
  RAJ.modelCount++;
  this.rdfaEnabled=false;

if (options) window.log.debug("Loading Model: "+typeof(options)+typeof(options.type));
if ((typeof(options)=="object")&&typeof(options.type)=="undefined") {this.jsonObject=options;window.setTimeout("RAJ.CALLBACK_DONE_EDITING()", 100)}
if (options) if (typeof(options.type)!="undefined") {
 if (options.type=="json") {
        if (options.string) {this.jsonObject=pParseJson(sourceString);window.setTimeout("RAJ.CALLBACK_DONE_EDITING()", 100);}
        if (options.url) {this.jsonObject=pLoadJson(options.url);window.setTimeout("RAJ.CALLBACK_DONE_EDITING()", 100)}
    }
    if ((options.type=="xml")&&(options.url)) this.jsonObject=pLoadXml(options.url);
    if (options.type=="rdfa") {
        if (options.url) {this.jsonObject=pLoadRdfa(options.url); window.setTimeout("RAJ.CALLBACK_DONE_EDITING()", 100)}
}
}

if (RAJ.validating) {
    pCheckModel(this.jsonObject);
  }


  this.parse = function (sourceString,type) {
            if ((typeof(options)=="object")&&typeof(options.type)=="undefined") this.jsonObject=options;
            if (typeof(options.type)!="undefined") {
                if (options.type=="json") {
                    if (options.string) this.jsonObject=pParseJson(sourceString);
                    if (options.url) this.jsonObject=pLoadJson(options.url);
                }
                if ((options.type=="xml")&&(options.url)) this.jsonObject=pLoadXml(options.url);
                if (options.type=="rdfa") {
                    if (options.url=="undefined") this.jsonObject=pLoadRdfa(sourceString);
                }
            }
            return this.jsonObject
        }

 //RAJ.CALLBACK_DONE_PARSING();

}


 


/// <name>RToJ(rTriple)</name>
/// <summary>converts a RDFA.js triple into a valid RDF/JSON triple</summary>
RAJ.RToJ=function(rTriple) {
  var tempObj=new Object();
  tempObj[rTriple.subject.uri]=new Object();
  tempObj[rTriple.subject.uri][rTriple.predicate.uri]=new Array();
  tempObj[rTriple.subject.uri][rTriple.predicate.uri][0]=new Object();
  if (rTriple.object.uri) tempObj[rTriple.subject.uri][rTriple.predicate.uri][0].value=rTriple.object.uri;
  if (rTriple.object.value) tempObj[rTriple.subject.uri][rTriple.predicate.uri][0].value=rTriple.object.value;
  if (rTriple.object.uri) tempObj[rTriple.subject.uri][rTriple.predicate.uri][0].type="uri";
  if (rTriple.object.value) tempObj[rTriple.subject.uri][rTriple.predicate.uri][0].type="literal";
  if (rTriple.object.lang) tempObj[rTriple.subject.uri][rTriple.predicate.uri][0].lang=rTriple.object.lang;
  if (rTriple.object.datatype) tempObj[rTriple.subject.uri][rTriple.predicate.uri][0].datatype=rTriple.object.datatype;
  //window.log.debug(rTriple.toSource());
  //window.log.debug(tempObj.toSource());
  return tempObj;
}

/// <name>JToR(jTriple)</name>
/// <summary>implemented soon if needed</summary>
RAJ.JToR = function(jTriple) {
}



})()

