
/**
* This file contains code to handle determining the current browser.
* It allows Javascript code to check if the current browser satisfies
* a list of constraints which can include Browser name, operating system, and version.
* The format is [browser name].[os name][op][version].  
*   where: op can be:  ==, <, >, !=, <=, >=
* To use simply pass an expression to  coreweb.common.Browser.isBrowser(expression);
* Some examples of expressions are:
*     Expression                        Description - isBrowser(expression) evaluates to true if...
*       .mac                            The user is running Mac
*       .linux                          The user is running Linux
*       .win                            The user is running Windows
*       ie.mac                          The user is running IE on Mac 
*       !ie.mac                         The user is not running IE on Mac
*       safari.mac >= 1.2               The user is running Safari version 1.2 or higher on a Mac
*       safari < 1.2
*       netscape.linux                  The user is running Netscape on Linux
*       netscape.windows
*       !netscape.windows               The user is not running Nescape on Linux
*       ie.windows                      The user is running IE on Windows
* 
* Or and And expressions are also supported (nested expressions are not yet supported):
*  ie.mac || safari < 1.2 || netscape < 7.2
*
* The application server sets the current browser data in the 'questia.Dictionary.browser'
* 
* @author Jeff Tassin
*/


questia.Package( "coreweb.common" );

__logger = function(msg) {
	// ignore for dv.
}

coreweb.common.BrowserTag = function() {
      this.browser = null;
      this.op = null;
      this.version = null;
      this.os = null;
      this.negate = null;
      
      this.toString=function(){
	  	 var result = "BrowserTag-browser: "+this.browser+", op: " + this.op + ", version = " + this.version + ", os: " + this.os + ", negate: " + this.negate;
	  	 return result;
      }            
      this.evaluate = function( browserProps ) {
         var result = this._evaluate(browserProps);
         if (this.negate)
            return !result;
         else
            return result;
      }

      this._evaluate = function( browserProps ) {
      	 if ( !browserProps )
      	 	throw "BrowserTag.evaluate browserProps == null";
      	 	
         if ("*" == this.browser) {
            return true;
         }
         /** check that the browser names are the same */
         if (!this.compare(this.browser, browserProps.browser)) {
            return false;
         }

         var sos = this.os != null ? this.os.toLowerCase() : "";
         sos = sos == 'microsoft' ? 'windows' : sos;
         var sbos = browserProps.os != null ? browserProps.os.toLowerCase() : "";
         sbos = sbos == 'microsoft' ? 'windows' : sbos;
         if (!this.compare( sos, sbos )) {
            return false;
         }
         if (this.op == null || this.op.length == 0 ) {
            return true;
         }

         // current supported operators: <, >, =, <=, >=, !=, ==,
         
         var bversion = browserProps.version;
         if (this.op.length == 1) {
            var c1 = this.op.charAt(0);
            switch (c1) {
            case '>':
               return bversion > this.version;
            case '<':
               return bversion < this.version;
            case '=':
               return bversion == this.version;
            default:
               throw "Invalid operator: " + this.browser + this.op + this.version;
            }
         } else if (this.op.length == 2) {
            var c1 = this.op.charAt(0);
            var c2 = this.op.charAt(1);
            switch (c1) {
            case '>':
               if (c2 == '=') {
                  return bversion >= this.version;
               }
            case '<':
               if (c2 == '=')
                  return bversion <= this.version;
            case '=':
               if (c2 == '=')
                  return bversion == this.version;
            case '!':
               if (c2 == '=')
                  return bversion != this.version;
            }
            throw "Invalid operator: " + this.browser + this.op + this.version;
         } else {
            throw "Invalid operator: " + this.browser + this.op + this.version;
         }
      }

      this.compare = function(tagValue, val2) {
         if (tagValue == null || tagValue.length == 0) {
            return true;
         } else if ( val2 == null )  {
             return false;
         } else {
            tagValue = coreweb.common.trim(tagValue);
            val2 = coreweb.common.trim(val2);
            return tagValue.toLowerCase() == val2.toLowerCase();
         }
      }

}

coreweb.common.BrowserTag.create = function(browser,op,version ) {

	this.convertName = function(browserName) {
		browserName = browserName.toLowerCase();
        if ("mac" == browserName) {
           return "Macintosh";
        } else if ("win" == browserName || "windows" == browserName ) {
           return "Microsoft";
        } else {
           return browserName;
        }	
	}

	var tag = new coreweb.common.BrowserTag();
	var negate = false;
    var c1 = browser.charAt(0);
    if (c1 == '!') {
         negate = true;
         browser = browser.substring(1,browser.length - 1);
         tag.negate = true;
    }

    var ppos = browser.indexOf('.');
    if (ppos >= 0) {
         tag.browser = browser.substring(0, ppos);
         tag.os = this.convertName(browser.substring(ppos + 1, browser.length));
    } else {
        tag.browser = browser;
    }
    tag.op = op;
    tag.version = version;
    if (op != null && negate) {
        throw "BrowserTag invalid.  ! and operators cannot be used together: " + browser + op + version;
    }
    return tag;
}



coreweb.common.Browser = {};
coreweb.common.Browser.isBrowser = function( exprList ) {
    var _expressions = [];
	
	this.addTag = function( bTag, logical ) {
		__logger( "addTag: " + bTag.browser + "  logical: " + logical );
		if( bTag ) {
			_expressions.push( bTag );
			if ( logical )
				_expressions.push( logical );
		}
	}
	
	this.evaluateRule = function(expr) {
		var pattern = /([!]?[a-zA-Z]+([\.][a-zA-Z]+)?\s*)((>=|<=|<|>|==|=|!=)(\s*[0-9]+(\.[0-9]+)?))?/;
		var result = expr.match(pattern);
		if ( result != null ) {
			var vos = result[1];
			var vop = result[4];
			var vversion= result[5];
			var browserTag = { browser: vos, op: vop, version: vversion };
			__logger( "browser matched... " + browserTag.browser + "  op: " + browserTag.op + "   version: " + browserTag.version );
			return browserTag;
		}
	}

	this.evaluate = function(exprList) {
		var last=0;
		var pattern = /&&|\|\|/g;
		while((match = pattern.exec( exprList )) != null) {
			var expr = exprList.substring(last, match.index);
			var logical = exprList.substring(match.index,match.index+2);
			last = pattern.lastIndex;
			this.addTag(this.evaluateRule( expr ), logical );
		}
		if ( last == 0 ) {
			this.addTag(this.evaluateRule(exprList));
		} else {
			var expr = exprList.substring(last, exprList.length );
			this.addTag(this.evaluateRule( expr ));
		}
	}
	
	this.evaluate(exprList);
	var lastlogical;
	var lastresult = true;
	for( var i=0; i < _expressions.length; i++ ) {
         var expr = _expressions[i];
         __logger( "expr: " + expr + " at i=" + i );
	}
	
	for( var i=0; i < _expressions.length; i++ ) {
         var expr = _expressions[i];
         var btag = new coreweb.common.BrowserTag.create( expr.browser, expr.op, expr.version );
         __logger( btag.toString() );
		 var result = btag.evaluate( questia.Dictionary.browser );
         if ( lastlogical != null ) {
            if ( lastlogical == '||' && (result || lastresult))
               return true;
            else if ( lastlogical == '&&' && !(result && lastresult) )
               return false;
         } 
         lastresult = result;
         if ( (i+1) < _expressions.length ) {
         	i++;
         	lastlogical = _expressions[i];
         	if ( lastlogical != '&&' && lastlogical != '||') 
         	   throw "Logical operand expected at index i=" + i + "  " + lastlogical;
         }
      }
      return lastresult;
}

coreweb.common.Browser.isIE6 = function( exprList ) {
  return coreweb.common.Browser.isBrowser("ie.windows < 7");
}

coreweb.common.Browser.isIE7 = function( exprList ) {
	return coreweb.common.Browser.isBrowser("ie.windows < 8") && coreweb.common.Browser.isBrowser("ie.windows > 6");
}

 
//questia.Dictionary.browser = {browser: 'Firefox', version: 1.2, os: 'Linux'};
//evalBrowser = [{browser: 'Firefox', version: 1.0, op: '<=', os: 'Linux'}, "||", {browser: 'ie', os: 'mac' }]
//evalBrowser = {browser: 'Firefox', version: 1.0, op: '<=', os: 'Linux'};
//evalBrowser = "FireFox < 1.2 || ie.mac";
//evalBrowser = "ie.mac || Firefox";
//__logger( "evalbrowser: " + coreweb.common.Browser.isBrowser( evalBrowser ) );


