/************************************************************
Description: API for accessing a propriatery models database (this one is for cars)
Version:     1.1

Copyright 2010 Avi Halachmi, All rights reserved.
Any usage (comercial or other) is prohibited without prior approval by Avi Halachmi.

Written by: Avi Halachmi (avihpit@yahoo.com, Tel.: +972(54)7575-419)



-----------------------------
Changelog:

Version 1.0 (2010-02-26)
- Initial version

Version 1.1 (2010-03-03)
- Cleaned up APIs

Version 1.2 (2010-12-07)
- Multilingual DB support

************************************************************/
var debugObjContents={}, uknIX=0;
function dbgObj(obj, name){
    if (!name) name="unknown_"+(uknIX++);
    debugObjContents[name]=obj;
    if (document)
        document.___safecar_view_DBG=debugObjContents;
}

function getUrlParam(url, name){
    var res=null;
    url=(""+url).split("?");
    if (!url[1])
        return null;
        
        
    url="&"+url[1].split("#")[0];
    var search="&"+name+"=";
    var start=url.indexOf(search);
    if (start<0)
        return null;
        
    return url.substr(start+search.length).split("&")[0];
}

//returns an object containing generic properties of the database
//e.g.: {lang:"en", dir:"ltr", timestamp:1267637956, translations:{model:"Model", engine:"Engine", ...}
function getDbProperties(db){
    var res={};
    res.languages    =  db.languages;
    res.timestamp    =  db.unixTimestamp*1000;
    res.translations =  db.translations;
    
    return res;
}

function getBestMatchingLanguageCode(db, requestedLangCode){
    requestedLangCode=(""+requestedLangCode).toLowerCase();
    for (var langIx in db.languages.codes)
        if (db.languages.codes[langIx]==requestedLangCode)
            return requestedLangCode;
            
    return db.languages.defaultLang;
}

//returns an object containing global properties for a specific maker.
//e.g.:
//{name:"Honda", categories:["Accord", "CBR", ..], engines:[600, 2000, ...], minYear:1997, maxYear:2010}
function getPropertiesForMakerIx(db, makerIx, langCode){
    //TODO: validate lang code
    var maker=_isValidMakerIx(db, makerIx);
    if (!maker) return null;
        
    var ix=db["makers.index"], res={};
    
    res.name=       maker[ix["maker.name"]][langCode];
    res.categories= maker[ix["maker.catsIx"]][langCode];
    res.engines=    maker[ix["maker.enginesIx"]];
    res.minYear=    maker[ix["maker.minYear"]];
    res.maxYear=    maker[ix["maker.maxYear"]];
    
    return res;
}



//returns an array of engine volumes for category index in maker, or for all models of maker if catIx==-1
//e.g.: [600, 2000, 2200, ...]
function getEnginesForCat(db, makerIx, catIx, langCode){
    var maker=_isValidMakerIx(db, makerIx); if (!maker) return null;
    if (catIx!=-1 && !_isValidMakerIxCategoryIx(db, makerIx, catIx, langCode)) return null;
   
    var ix=db["makers.index"], models=maker[ix["maker.models"]];
    
    //if (catIx==-1)//engines list depends on categories which are available at this language. can't return all engines automatically
    //    return maker[ix["maker.enginesIx"]];

    var tmp={};
    for (var m in models){
        var model=models[m];
        var modelCatIx=model[ix["model.catIx"]];
        //alert("models["+m+"].cat="+model[ix["model.catIx"]]);
        if (catIx<0 && _isValidMakerIxCategoryIx(db, makerIx, modelCatIx, langCode) || modelCatIx==catIx)
            tmp[maker[ix["maker.enginesIx"]][model[ix["model.engineIx"]]]]=1;
    }
    var res=[];
    for (var i in tmp)
        res.push(i);

    res.sort();
    return res;
}


/* //returns a display row (=model in maker) and its properties:
e.g.:
{
    //actual data for display
    maker:  "Honda",
    Model:  "RCV212",
    engine: 800,
    years:  {
        2003:{makat:"123-333"},
        2004:{makat:"123-444"},
        2008:{makat:"123-888"},
        
        //a year object may also have some debug data that isn't available on production DB:
        // debug_line: line in the original excel file from which the DB was created
        2010:{makat:"123-1010", debug_line:5534}
    },
    
    //some extra data that might help with display
    makerIx:        12,
    modelIx:        8,
    makerMaxYear:   2010,
    makerMinYear:   1997,
    
    //some debug data that isn't available on production DB:
    //model id in the original excel file from which the DB was created
    debug_modelId: 19342,
}
*/
function getDisplayRow(db, makerIx, modelIx){
    var maker=_isValidMakerIx(db, makerIx);
    var model=_isValidMakerIxModelIx(db, makerIx, modelIx);
    if (!maker || !model)  return null;
    var ix=db["makers.index"], res={};
    
    //some maker-related generic data for this row which may be helpful while displaying the row
    res.makerIx=makerIx;
    res.modelIx=modelIx;
    res.makerMaxYear=maker[ix["maker.maxYear"]];
    res.makerMinYear=maker[ix["maker.minYear"]];
    
    //actual data that can be displayed
    res.maker=  maker[ix["maker.name"]];
    res.engine= maker[ix["maker.enginesIx"]][model[ix["model.engineIx"]]];
    res.model=  model[ix["model.name"]];
    
    res.years={};
    
    for (var i in model[ix["model.years"]]){
        var yearCode=model[ix["model.years"]][i];
        var yearValue=yearCode + maker[ix["maker.minYear"]];
        
        var makat=model[ix["model.makat"]]
        var debug_line=undefined;
        
        var exceptions=model[ix["model.exceptionsObj"]];
        if (exceptions)
            exceptions=exceptions[yearCode];
        if (exceptions){
            if (exceptions[ix["exception.makat"]]){
                makat=exceptions[ix["exception.makat"]];
            }
            
            //debug data. not available in production DB
            if (exceptions[ix["exception.debug.line"]]){
                debug_line=exceptions[ix["exception.debug.line"]];
            }
        }
        
        if (!isNaN(makat))
            makat=1*makat+maker[ix["maker.baseMakatIfNumber"]];
            
        res.years[yearValue]={makat:makat};
        if (debug_line)
            res.years[yearValue].debug_line=debug_line;
    }
    
    //debug data. not available in production DB
    if (model[ix["model.debug.id"]])
        res.debug_modelId=model[ix["model.debug.id"]]
    
    return res;
}

/*
returns an array of rows, each row in the format returned by getDisplayRow() (see above)

filter is an object in the form of:
{
    makerIx:<required-maker-ix>,
    categoryIx:<required-category-ix>,
    engine:<required-engine-volume>,
}
where a value of -1 for any of the pairs indicates 'all'
*/
function getDisplayRowsArray(db, filter, langCode){
    //dbg("filtering rows for: maker:"+filter.makerIx+", cat:"+filter.categoryIx+", engine:"+filter.engine);
    var ix=db["makers.index"], dbm=db["makers"];
    var _filter={makerIx:-1, categoryIx:-1, engine:-1};
    if (filter !== undefined){
        if (filter.makerIx!==undefined)     _filter.makerIx=filter.makerIx;
        if (filter.categoryIx!==undefined)  _filter.categoryIx=filter.categoryIx;
        if (filter.engine!==undefined)      _filter.engine=filter.engine;
    }
    var res=[];
    
    for (var makerIx in dbm){
        var maker=dbm[makerIx];
        
        if (_filter.makerIx==-1 || _filter.makerIx==makerIx){
        
            for (var modelIx in maker[ix["maker.models"]]){
                var model=maker[ix["maker.models"]][modelIx];
                
                if (
                        _isValidMakerIxCategoryIx(db, filter.makerIx, model[ix["model.catIx"]], langCode)
                        &&
                        (_filter.categoryIx==-1 || _filter.categoryIx==model[ix["model.catIx"]])
                        &&
                        (_filter.engine==-1 || filter.engine==maker[ix["maker.enginesIx"]][model[ix["model.engineIx"]]])
                        &&
                        ((""+model[ix["model.name"]][langCode]).indexOf("*")<0)
                    ){
                        res.push(getDisplayRow(db, makerIx, modelIx));
                }
            }
        }
    }
    return res;
}



//internal functions

//coerceable to bool, but returns actual maker object if valid
function _isValidMakerIx(db, makerIx){
    if (!(0 <= makerIx && makerIx < db["makers"].length))
        return false;
        
    return db["makers"][makerIx];
}

function _isValidMakerIxCategoryIx(db, makerIx, categoryIx, langCode){
    var maker=_isValidMakerIx(db, makerIx), ix=db["makers.index"];
    if (!maker) return false;

    //alert("searching catIx: "+categoryIx+", cats for lang "+langCode+": "+maker[ix["maker.catsIx"]][langCode]);
    return (0 <= categoryIx &&
            categoryIx < maker[ix["maker.catsIx"]][langCode].length &&
            (""+maker[ix["maker.catsIx"]][langCode][categoryIx]).indexOf("*")<0
            );
}

//coerceable to bool, but returns actual model object if valid
function _isValidMakerIxModelIx(db, makerIx, modelIx){
    var maker=_isValidMakerIx(db, makerIx), ix=db["makers.index"];
    if (!maker) return false;

    if (!(0 <= modelIx && modelIx < maker[ix["maker.models"]].length))
        return false;
        
    return maker[ix["maker.models"]][modelIx];
}

