/*
 the following libs and css must be included
 <script type="text/javascript" language="JavaScript1.2" src="/js/jquery.min.js"></script>
 <script src="/js/pipingCallout/simpleCallout.js"></script>
 <link rel="stylesheet" type="text/css" href="/js/pipingCallout/pipingCallout.css"/>

 usage:
 assign simpleCalloutMouseOver(event, headerName, mainText) and simpleCalloutMouseMove(event) for

 example:
 <img... onmouseover="simpleCalloutMouseOver(event, "", "Mouse Over Text");" onmousemove="simpleCalloutMouseMove(event);"/>

 */
var SIMPLE_CALLOUT_DIV = "simpleCalloutDiv";
var j$ = jQuery.noConflict();
var currentElementSimpleCallout;
var timeAfterClose = 0;
var mousePosSimpleCallout = {posX:0, posY:0};
var closeTimeoutSimpleCallout;

function simpleCalloutMouseMove(e) {
  e = e || window.event;
  if (e.pageX || e.pageX) {
    mousePosSimpleCallout.posX = e.pageX;
    mousePosSimpleCallout.posY = e.pageY;
  }
  if (e.clientX || e.clientY) {
    mousePosSimpleCallout.posX = e.clientX + document.body.scrollLeft
        + document.documentElement.scrollLeft;
    mousePosSimpleCallout.posY = e.clientY + document.body.scrollTop
        + document.documentElement.scrollTop;
  }
}
function simpleCalloutMouseOverByObject(e, obj){
  e = e || window.event;
  var divObject = document.getElementById("div"+obj.id);
  if(divObject!=null)
    simpleCalloutMouseOver(e, "", divObject.innerHTML);
  divObject = null;
}
function simpleCalloutMouseOver(e, headerName, mainText) {
  e = e || window.event;
  var currentTime = new Date().getTime();
  if ((currentTime - timeAfterClose) < 200)
    return;
  var div = j$("#" + SIMPLE_CALLOUT_DIV);
  var currentTarget = (e.target || e.srcElement);
  if (div != null && div.is(':visible') && currentElementSimpleCallout == currentTarget)
    return;
  currentElementSimpleCallout = currentTarget;
  var calloutHeaderName = (headerName == null ? "" : headerName);
  var calloutMainText = (mainText == null ? "" : mainText);
  if (div == null || div.length == 0) {
    initPipingCalloutDialog();
  }
  showSimpleCallout(calloutHeaderName, calloutMainText);
  currentTime = div = currentTarget = calloutHeaderName = calloutMainText = null;
}

function showSimpleCallout(headerName, mainText) {
  showCalloutTimeout(headerName, mainText);
}

function setData(headerName, mainText) {
  j$("#calloutHeaderSpan").html(headerName);
  j$("#calloutTextDiv").html(mainText);
}

function showCalloutTimeout(headerName, mainText) {
  setTimeout(function () {showCalloutNearCursor(headerName, mainText)}, 500);
}
function  showCalloutNearCursor(headerName, mainText) {
  setData(headerName, mainText);
  var tPosX = mousePosSimpleCallout.posX + "px";
  var tPosY = (mousePosSimpleCallout.posY + 20) + "px";
  j$('#' + SIMPLE_CALLOUT_DIV).css({top: tPosY, left: tPosX}).show();
  closeSimpleCallOutDivTimeOut();
  tPosX = tPosY = null;
}

function initPipingCalloutDialog() {
  appendPipingCalloutDiv();
}

function appendPipingCalloutDiv() {
  j$("body").append('' +
                   '<div style="border: 1px gray solid; display: none; z-index: 900; position: absolute;" id="' + SIMPLE_CALLOUT_DIV +
                   '" class="flora ui-dialog-content calloutMainDiv">' +
                   '<table cellpadding="3" cellspacing="0" bgcolor="white" >' +
                   '<tbody>' +
                   '<tr class="calloutHeaderTr">' +
                   '<td align="left">' +
                   '<span id="calloutHeaderSpan" style="padding-left:3px;"></span>' +
                   '</td>' +
                   '<td align="right">' +
                   '<a id="pipingCalloutCloseElement" onclick="closeSimpleCallOutDiv();" class="pipingCalloutCloseA">X</a>' +
                   '</td>' +
                   '</tr>' +
                   '<tr>' +
                   '<td colspan="2">' +
                   '<div id="calloutTextDiv" class="calloutTextDiv"></div>' +
                   '</td>' +
                   '</tr>' +
                   '</tbody>' +
                   '</table>' +
                   '</div>');
}

function closeSimpleCallOutDiv() {
  timeAfterClose = new Date().getTime();
  j$('#' + SIMPLE_CALLOUT_DIV).hide();
}

function closeSimpleCallOutDivTimeOut() {
  if (closeTimeoutSimpleCallout != null) clearTimeout(closeTimeoutSimpleCallout);
  closeTimeoutSimpleCallout = setTimeout(function () {closeSimpleCallOutDiv()}, 2000);
}
String.prototype.trim=function()
{ return this.leftTrim().rightTrim();
};
String.prototype.leftTrim=function()
{ return this.replace(/^\s*(.*)/,"$1");
};
String.prototype.rightTrim=function()
{ return this.replace(/^(.*\S)(\s*)$/,"$1");
};

//------------------------------------------------------------------
//    Fast string concatenation in JS
//------------------------------------------------------------------
function StringBuffer() {
  this.buffer = [];
}

StringBuffer.prototype.append = function append(string) {
  this.buffer.push(string);
  return this;
};

StringBuffer.prototype.toString = function toString() {
  return this.buffer.join("");
};
/*
    //Usage: <script language="JavaScript" src="/Member/js/keyEvents.js" type="text/javascript"></script>
    //in script you shold use if (isPressedEnter(event))...
*/
var version = 0;
if (navigator.appVersion.indexOf("MSIE") != -1) {
  temp = navigator.appVersion.split("MSIE")
  version = parseFloat(temp[1])
}

var is_IE = false;
if (version >= 5.5) //NON IE browser will return 0
  is_IE = true;

function isPressedEnter(evt)
{ try{
      if (is_IE)
      {
        evt = window.event;
        //explorer
        try {
          if (evt != 'undefined' &&
              evt.keyCode != 'undefined' &&
              evt.keyCode == 13) {
            return true;
          }
        }
        catch(e) {
          alert(e);
        }
      }
      else
      {
        event = evt;
        //mozilla
        if (event != null &&
            event != 'undefined' &&
            event.keyCode != 'undefined' &&
            event.keyCode == 13) {
          return true;
        }
      }
  }
  catch(e){
      alert(e);
  }
  return false;
}

function isPressedTab(evt)
{ try{
      if (is_IE)
      {
        evt = window.event;
        //explorer
        try {
          if (evt != 'undefined' &&
              evt.keyCode != 'undefined' &&
              evt.keyCode == 9) {
            return true;
          }
        }
        catch(e) {
          alert(e);
        }
      }
      else
      {
        event = evt;
        //mozilla
        if (event != null &&
            event != 'undefined' &&
            event.keyCode != 'undefined' &&
            event.keyCode == 9) {
          return true;
        }
      }
  }
  catch(e) {
      alert(e);
  }
  return false;
}
/*
*  name - id HTML object
*  hide - (true|false)
*/
function MM_HideLayer(name,hide){
  var obj = document.getElementById(name);
  if(obj!=null){
    var v = (hide)?'hidden':'visible';
    obj.style.visibility = v;
  }
}
function MM_preloadImages()
{ //v3.0
  var d=document;
  if(d.images)
  { if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments;
    for(i=0; i<a.length; i++)
    { if (a[i].indexOf("#")!=0)
      { try{d.MM_p[j]=new Image(); d.MM_p[j++].src=a[i];}catch(ex){}
      }
    }
  }
}
function MM_swapImgRestore()
{ //v3.0
  var i,x,a=document.MM_sr;
  for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}
function MM_findObj(n, d)
{ //v4.0
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
  d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && document.getElementById) x=document.getElementById(n); return x;
}
function MM_swapImage()
{ //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array;
  for(i=0;i<(a.length-2);i+=3)
  { if ((x=MM_findObj(a[i]))!=null)
    {  document.MM_sr[j++]=x;
       if(!x.oSrc) x.oSrc=x.src;
       x.src=a[i+2];
    }
  }
}
/*
function disableOther(frn_name)
{ //v 2.7
  if (true) return;
  var i=0;var frm=findForm(frm_name);
  while (i<frm.length)
  { if((frm[i]!=null)&&(frm[i].name!=null))
     { var r="";var value="";
       if ((frm[i].name.indexOf("other")>=0)&&(frm[i].value.length==0))
       {  var k=frm[i].name.indexOf("other")+5;r+="R";
          while((frm[i].name.charAt(k)!='_')&&(k<frm[i].name.length)) {r+=frm[i].name.charAt(k);k++;}
          while(k<frm[i].name.length) {value+=frm[i].name.charAt(k);k++;}
       }
       if(r.length>0)
       {  var j=0;var found=false; var val="";
          while(j<frm.length)
          {  if((frm[j]!=null)&&(frm[j].name!=null))
             {  val=""+frm[j].value;
                if ((frm[j].name.indexOf(r)>=0)&&(val.indexOf(value)>=0)) {found=true;break;}
             } j++;
          }  if (found) {frm[i].disabled=true;alert(frm[i].name+" - disabled!");}
       }
     } i++;
  }
}
*/
/*
	Default driver template for JS/CC generated parsers for JScript

	WARNING: Do not use for parsers that should run as browser-based JavaScript!
			 Use driver_web.js_ instead!

	Features:
	- Parser trace messages
	- Step-by-step parsing
	- Integrated panic-mode error recovery
	- Pseudo-graphical parse tree generation

	Written 2007 by Jan Max Meyer, J.M.K S.F. Software Technologies

	This is in the public domain.
*/

//@if( @_jscript_version >= 7 )
//import System;
//@end


/*
The "ROW_LOGIC" is a wildcard, where an optional, unique name will be inserted by
JS/CC when the parser is constructed. This enables the possibility to use multiple
different parsers in one project or script.


call parseExpressionLogic_ROW_LOGIC(expression, surveyQuestions, surveyResults, isOnlyValidate)
expression is "Q1.A2",
surveyQuestions is a map of question ids and answer ids for current survey,
surveyResults is a map of answer ids with results,
isOnlyValidate - true if need to validate expression for survey structure (without results)


If need to change validation behaviour, you can ovveride functions of parser_ROW_LOGIC:
 isVoted_ROW_LOGIC(expression) // if isOnlyValidate = false
 validateBySurveyStructure_ROW_LOGIC(expression) // if isOnlyValidate = true

 this function are calling for checking(validating) each token of logical expression, i.e. if you have Q1.A1 AND Q2.A3, then one of the functions above will be
  called two times, first call for chacking Q1.A1, second - for Q2.A3.

*/



var result_ROW_LOGIC = true;
var isOnlyValidate_ROW_LOGIC = true;
var errors_ROW_LOGIC = "";
var rowLogicRegExp = new RegExp("Q(\\d+)(?:.A(\\?|\\d+|\\*))?(?:.C(\\d+))?((<>|==)[^\\s]+)?");

var parser_ROW_LOGIC = {
  isVoted_ROW_LOGIC: function (expression) {
    var token = rowLogicRegExp.exec(expression);
    var questionId = token[1];
    var answerId = token[2];
    var columnNum = token[3];
    var matchResult = token[4];

    if (questionId == "" || isNaN(questionId)) questionId = null;
    if (answerId == "" || isNaN(answerId)) answerId = null;
    if (columnNum == "" || isNaN(columnNum)) columnNum = null;
    if (columnNum != null && answerId != null && columnNum.length > 0) columnNum = parseInt(columnNum) - 1; //Q12345.A112345.C1, but Q12345.C12345
    return validateRequiredElement(questionId, answerId, columnNum, matchResult);
  },

  validateBySurveyStructure_ROW_LOGIC: function (expression) {
    var token = rowLogicRegExp.exec(expression);
    var questionId = token[1];
    var answerId = token[2];
    var columnNum = token[3];
    var matchResult = token[4];

    if (questionId == "" || isNaN(questionId)) questionId = null;
    if (answerId == "" || isNaN(answerId)) answerId = null;
    if (columnNum == "" || isNaN(columnNum)) columnNum = null;
    return validateRequiredElementBySurveyStructure(questionId, answerId, columnNum, matchResult);
  }
}

function getErrors_ROW_LOGIC() {
  return errors_ROW_LOGIC;
}

function checkExpression_ROW_LOGIC(expression) {
  if (isOnlyValidate_ROW_LOGIC) return parser_ROW_LOGIC.validateBySurveyStructure_ROW_LOGIC(expression);
  else return parser_ROW_LOGIC.isVoted_ROW_LOGIC(expression);
}

function saveResult_ROW_LOGIC(expression){
  result_ROW_LOGIC = expression;
}

function parseExpressionLogic_ROW_LOGIC(expression, isOnlyValidate) {

  isOnlyValidate_ROW_LOGIC = isOnlyValidate;
  result_ROW_LOGIC = true;

  var error_offsets = new Array();
  var error_lookaheads = new Array();
  var error_count = 0;
  if( ( error_count = __ROW_LOGICparse( expression, error_offsets, error_lookaheads ) ) > 0 ) {
      result_ROW_LOGIC = false;
      for( i = 0; i < error_count; i++ ) {
        errors_ROW_LOGIC += 'Parse error near \"' + expression.substr( error_offsets[i] ) + '\", expecting \"' + error_lookaheads[i].join() + '\"' + "\n";
      }
  }

  return result_ROW_LOGIC;

}


var ROW_LOGIC_dbg_withparsetree	= false;
var ROW_LOGIC_dbg_withtrace		= false;
var ROW_LOGIC_dbg_withstepbystep	= false;

function __ROW_LOGICdbg_print( text )
{
  alert(text);
//@if( @_jscript_version < 7 )
//	WScript.Echo( text );
//@else
//	print( text );
//@end
}

function __ROW_LOGICdbg_wait()
{
//@if( @_jscript_version < 7 )
//	WScript.StdIn.ReadLine()
//@else
//	Console.ReadLine();
//@end
}

function __ROW_LOGIClex( info )
{
	var state		= 0;
	var match		= -1;
	var match_pos	= 0;
	var start		= 0;
	var pos			= info.offset + 1;

	do
	{
		pos--;
		state = 0;
		match = -2;
		start = pos;

		if( info.src.length <= start )
			return 12;

		do
		{

switch( state )
{
	case 0:
		if( ( info.src.charCodeAt( pos ) >= 9 && info.src.charCodeAt( pos ) <= 10 ) || info.src.charCodeAt( pos ) == 13 || info.src.charCodeAt( pos ) == 32 ) state = 1;
		else if( info.src.charCodeAt( pos ) == 33 ) state = 2;
		else if( info.src.charCodeAt( pos ) == 40 ) state = 3;
		else if( info.src.charCodeAt( pos ) == 41 ) state = 4;
		else if( info.src.charCodeAt( pos ) == 38 ) state = 9;
		else if( info.src.charCodeAt( pos ) == 65 || info.src.charCodeAt( pos ) == 97 ) state = 11;
		else if( info.src.charCodeAt( pos ) == 78 || info.src.charCodeAt( pos ) == 110 ) state = 12;
		else if( info.src.charCodeAt( pos ) == 79 || info.src.charCodeAt( pos ) == 111 ) state = 13;
		else if( info.src.charCodeAt( pos ) == 81 || info.src.charCodeAt( pos ) == 113 ) state = 14;
		else if( info.src.charCodeAt( pos ) == 124 ) state = 15;
		else state = -1;
		break;

	case 1:
		state = -1;
		match = 1;
		match_pos = pos;
		break;

	case 2:
		state = -1;
		match = 8;
		match_pos = pos;
		break;

	case 3:
		state = -1;
		match = 2;
		match_pos = pos;
		break;

	case 4:
		state = -1;
		match = 3;
		match_pos = pos;
		break;

	case 5:
		state = -1;
		match = 7;
		match_pos = pos;
		break;

	case 6:
		state = -1;
		match = 6;
		match_pos = pos;
		break;

	case 7:
		if( ( info.src.charCodeAt( pos ) >= 48 && info.src.charCodeAt( pos ) <= 57 ) ) state = 7;
		else if( info.src.charCodeAt( pos ) == 46 ) state = 18;
		else if( info.src.charCodeAt( pos ) == 60 ) state = 19;
		else if( info.src.charCodeAt( pos ) == 61 ) state = 20;
		else state = -1;
		match = 5;
		match_pos = pos;
		break;

	case 8:
		if( ( info.src.charCodeAt( pos ) >= 0 && info.src.charCodeAt( pos ) <= 31 ) || ( info.src.charCodeAt( pos ) >= 33 && info.src.charCodeAt( pos ) <= 254 ) ) state = 8;
		else state = -1;
		match = 4;
		match_pos = pos;
		break;

	case 9:
		if( info.src.charCodeAt( pos ) == 38 ) state = 5;
		else state = -1;
		break;

	case 10:
		if( ( info.src.charCodeAt( pos ) >= 48 && info.src.charCodeAt( pos ) <= 57 ) ) state = 10;
		else if( info.src.charCodeAt( pos ) == 60 ) state = 19;
		else if( info.src.charCodeAt( pos ) == 61 ) state = 20;
		else state = -1;
		match = 5;
		match_pos = pos;
		break;

	case 11:
		if( info.src.charCodeAt( pos ) == 78 || info.src.charCodeAt( pos ) == 110 ) state = 16;
		else state = -1;
		break;

	case 12:
		if( info.src.charCodeAt( pos ) == 79 || info.src.charCodeAt( pos ) == 111 ) state = 17;
		else state = -1;
		break;

	case 13:
		if( info.src.charCodeAt( pos ) == 82 || info.src.charCodeAt( pos ) == 114 ) state = 6;
		else state = -1;
		break;

	case 14:
		if( ( info.src.charCodeAt( pos ) >= 48 && info.src.charCodeAt( pos ) <= 57 ) ) state = 7;
		else state = -1;
		break;

	case 15:
		if( info.src.charCodeAt( pos ) == 124 ) state = 6;
		else state = -1;
		break;

	case 16:
		if( info.src.charCodeAt( pos ) == 68 || info.src.charCodeAt( pos ) == 100 ) state = 5;
		else state = -1;
		break;

	case 17:
		if( info.src.charCodeAt( pos ) == 84 || info.src.charCodeAt( pos ) == 116 ) state = 2;
		else state = -1;
		break;

	case 18:
		if( info.src.charCodeAt( pos ) == 67 || info.src.charCodeAt( pos ) == 99 ) state = 21;
		else if( info.src.charCodeAt( pos ) == 65 || info.src.charCodeAt( pos ) == 97 ) state = 25;
		else state = -1;
		break;

	case 19:
		if( info.src.charCodeAt( pos ) == 62 ) state = 22;
		else state = -1;
		break;

	case 20:
		if( info.src.charCodeAt( pos ) == 61 ) state = 22;
		else state = -1;
		break;

	case 21:
		if( ( info.src.charCodeAt( pos ) >= 48 && info.src.charCodeAt( pos ) <= 57 ) ) state = 10;
		else state = -1;
		break;

	case 22:
		if( ( info.src.charCodeAt( pos ) >= 0 && info.src.charCodeAt( pos ) <= 31 ) || ( info.src.charCodeAt( pos ) >= 33 && info.src.charCodeAt( pos ) <= 254 ) ) state = 8;
		else state = -1;
		break;

	case 23:
		if( info.src.charCodeAt( pos ) == 67 || info.src.charCodeAt( pos ) == 99 ) state = 21;
		else state = -1;
		break;

	case 24:
		if( info.src.charCodeAt( pos ) == 60 ) state = 19;
		else if( info.src.charCodeAt( pos ) == 61 ) state = 20;
		else if( info.src.charCodeAt( pos ) == 46 ) state = 23;
		else if( ( info.src.charCodeAt( pos ) >= 48 && info.src.charCodeAt( pos ) <= 57 ) ) state = 24;
		else state = -1;
		match = 5;
		match_pos = pos;
		break;

	case 25:
		if( ( info.src.charCodeAt( pos ) >= 48 && info.src.charCodeAt( pos ) <= 57 ) ) state = 24;
		else state = -1;
		break;

}


			pos++;

		}
		while( state > -1 );

	}
	while( 1 > -1 && match == 1 );

	if( match > -1 )
	{
		info.att = info.src.substr( start, match_pos - start );
		info.offset = match_pos;


	}
	else
	{
		info.att = new String();
		match = -1;
	}

	return match;
}


function __ROW_LOGICparse( src, err_off, err_la )
{
	var		sstack			= new Array();
	var		vstack			= new Array();
	var 	err_cnt			= 0;
	var		act;
	var		go;
	var		la;
	var		rval;
	var 	parseinfo		= new Function( "", "var offset; var src; var att;" );
	var		info			= new parseinfo();

	//Visual parse tree generation
	var 	treenode		= new Function( "", "var sym; var att; var child;" );
	var		treenodes		= new Array();
	var		tree			= new Array();
	var		tmptree			= null;

/* Pop-Table */
var pop_tab = new Array(
	new Array( 0/* p' */, 1 ),
	new Array( 10/* p */, 1 ),
	new Array( 9/* expr */, 3 ),
	new Array( 9/* expr */, 3 ),
	new Array( 9/* expr */, 2 ),
	new Array( 9/* expr */, 3 ),
	new Array( 9/* expr */, 1 ),
	new Array( 11/* expr_complex */, 1 ),
	new Array( 11/* expr_complex */, 1 )
);

/* Action-Table */
var act_tab = new Array(
	/* State 0 */ new Array( 8/* "NOT" */,3 , 2/* "(" */,4 , 4/* "EXPRESSION_TEXT" */,6 , 5/* "EXPRESSION" */,7 ),
	/* State 1 */ new Array( 12/* "$" */,0 ),
	/* State 2 */ new Array( 7/* "AND" */,8 , 6/* "OR" */,9 , 12/* "$" */,-1 ),
	/* State 3 */ new Array( 8/* "NOT" */,3 , 2/* "(" */,4 , 4/* "EXPRESSION_TEXT" */,6 , 5/* "EXPRESSION" */,7 ),
	/* State 4 */ new Array( 8/* "NOT" */,3 , 2/* "(" */,4 , 4/* "EXPRESSION_TEXT" */,6 , 5/* "EXPRESSION" */,7 ),
	/* State 5 */ new Array( 12/* "$" */,-6 , 6/* "OR" */,-6 , 7/* "AND" */,-6 , 3/* ")" */,-6 ),
	/* State 6 */ new Array( 12/* "$" */,-7 , 6/* "OR" */,-7 , 7/* "AND" */,-7 , 3/* ")" */,-7 ),
	/* State 7 */ new Array( 12/* "$" */,-8 , 6/* "OR" */,-8 , 7/* "AND" */,-8 , 3/* ")" */,-8 ),
	/* State 8 */ new Array( 8/* "NOT" */,3 , 2/* "(" */,4 , 4/* "EXPRESSION_TEXT" */,6 , 5/* "EXPRESSION" */,7 ),
	/* State 9 */ new Array( 8/* "NOT" */,3 , 2/* "(" */,4 , 4/* "EXPRESSION_TEXT" */,6 , 5/* "EXPRESSION" */,7 ),
	/* State 10 */ new Array( 7/* "AND" */,-4 , 6/* "OR" */,-4 , 12/* "$" */,-4 , 3/* ")" */,-4 ),
	/* State 11 */ new Array( 7/* "AND" */,8 , 6/* "OR" */,9 , 3/* ")" */,14 ),
	/* State 12 */ new Array( 7/* "AND" */,8 , 6/* "OR" */,-3 , 12/* "$" */,-3 , 3/* ")" */,-3 ),
	/* State 13 */ new Array( 7/* "AND" */,8 , 6/* "OR" */,-2 , 12/* "$" */,-2 , 3/* ")" */,-2 ),
	/* State 14 */ new Array( 12/* "$" */,-5 , 6/* "OR" */,-5 , 7/* "AND" */,-5 , 3/* ")" */,-5 )
);

/* Goto-Table */
var goto_tab = new Array(
	/* State 0 */ new Array( 10/* p */,1 , 9/* expr */,2 , 11/* expr_complex */,5 ),
	/* State 1 */ new Array(  ),
	/* State 2 */ new Array(  ),
	/* State 3 */ new Array( 9/* expr */,10 , 11/* expr_complex */,5 ),
	/* State 4 */ new Array( 9/* expr */,11 , 11/* expr_complex */,5 ),
	/* State 5 */ new Array(  ),
	/* State 6 */ new Array(  ),
	/* State 7 */ new Array(  ),
	/* State 8 */ new Array( 9/* expr */,12 , 11/* expr_complex */,5 ),
	/* State 9 */ new Array( 9/* expr */,13 , 11/* expr_complex */,5 ),
	/* State 10 */ new Array(  ),
	/* State 11 */ new Array(  ),
	/* State 12 */ new Array(  ),
	/* State 13 */ new Array(  ),
	/* State 14 */ new Array(  )
);



/* Symbol labels */
var labels = new Array(
	"p'" /* Non-terminal symbol */,
	"^" /* Terminal symbol */,
	"(" /* Terminal symbol */,
	")" /* Terminal symbol */,
	"EXPRESSION_TEXT" /* Terminal symbol */,
	"EXPRESSION" /* Terminal symbol */,
	"OR" /* Terminal symbol */,
	"AND" /* Terminal symbol */,
	"NOT" /* Terminal symbol */,
	"expr" /* Non-terminal symbol */,
	"p" /* Non-terminal symbol */,
	"expr_complex" /* Non-terminal symbol */,
	"$" /* Terminal symbol */
);



	info.offset = 0;
	info.src = src;
	info.att = new String();

	if( !err_off )
		err_off	= new Array();
	if( !err_la )
	err_la = new Array();

	sstack.push( 0 );
	vstack.push( 0 );

	la = __ROW_LOGIClex( info );

	while( true )
	{
		act = 16;
		for( var i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 )
		{
			if( act_tab[sstack[sstack.length-1]][i] == la )
			{
				act = act_tab[sstack[sstack.length-1]][i+1];
				break;
			}
		}

		/*
		_print( "state " + sstack[sstack.length-1] + " la = " + la + " info.att = >" +
				info.att + "< act = " + act + " src = >" + info.src.substr( info.offset, 30 ) + "..." + "<" +
					" sstack = " + sstack.join() );
		*/

		if( ROW_LOGIC_dbg_withtrace && sstack.length > 0 )
		{
			__ROW_LOGICdbg_print( "\nState " + sstack[sstack.length-1] + "\n" +
							"\tLookahead: " + labels[la] + " (\"" + info.att + "\")\n" +
							"\tAction: " + act + "\n" +
							"\tSource: \"" + info.src.substr( info.offset, 30 ) + ( ( info.offset + 30 < info.src.length ) ?
									"..." : "" ) + "\"\n" +
							"\tStack: " + sstack.join() + "\n" +
							"\tValue stack: " + vstack.join() + "\n" );

			if( ROW_LOGIC_dbg_withstepbystep )
				__ROW_LOGICdbg_wait();
		}


		//Panic-mode: Try recovery when parse-error occurs!
		if( act == 16 )
		{
			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "Error detected: There is no reduce or shift on the symbol " + labels[la] );

			err_cnt++;
			err_off.push( info.offset - info.att.length );
			err_la.push( new Array() );
			for( var i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 )
				err_la[err_la.length-1].push( labels[act_tab[sstack[sstack.length-1]][i]] );

			//Remember the original stack!
			var rsstack = new Array();
			var rvstack = new Array();
			for( var i = 0; i < sstack.length; i++ )
			{
				rsstack[i] = sstack[i];
				rvstack[i] = vstack[i];
			}

			while( act == 16 && la != 12 )
			{
				if( ROW_LOGIC_dbg_withtrace )
					__ROW_LOGICdbg_print( "\tError recovery\n" +
									"Current lookahead: " + labels[la] + " (" + info.att + ")\n" +
									"Action: " + act + "\n\n" );
				if( la == -1 )
					info.offset++;

				while( act == 16 && sstack.length > 0 )
				{
					sstack.pop();
					vstack.pop();

					if( sstack.length == 0 )
						break;

					act = 16;
					for( var i = 0; i < act_tab[sstack[sstack.length-1]].length; i+=2 )
					{
						if( act_tab[sstack[sstack.length-1]][i] == la )
						{
							act = act_tab[sstack[sstack.length-1]][i+1];
							break;
						}
					}
				}

				if( act != 16 )
					break;

				for( var i = 0; i < rsstack.length; i++ )
				{
					sstack.push( rsstack[i] );
					vstack.push( rvstack[i] );
				}

				la = __ROW_LOGIClex( info );
			}

			if( act == 16 )
			{
				if( ROW_LOGIC_dbg_withtrace )
					__ROW_LOGICdbg_print( "\tError recovery failed, terminating parse process..." );
				break;
			}


			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "\tError recovery succeeded, continuing" );
		}

		/*
		if( act == 16 )
			break;
		*/


		//Shift
		if( act > 0 )
		{
			//Parse tree generation
			if( ROW_LOGIC_dbg_withparsetree )
			{
				var node = new treenode();
				node.sym = labels[ la ];
				node.att = info.att;
				node.child = new Array();
				tree.push( treenodes.length );
				treenodes.push( node );
			}

			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "Shifting symbol: " + labels[la] + " (" + info.att + ")" );

			sstack.push( act );
			vstack.push( info.att );

			la = __ROW_LOGIClex( info );

			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "\tNew lookahead symbol: " + labels[la] + " (" + info.att + ")" );
		}
		//Reduce
		else
		{
			act *= -1;

			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "Reducing by producution: " + act );

			rval = void(0);

			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "\tPerforming semantic action..." );

switch( act )
{
	case 0:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 1:
	{
		 saveResult_ROW_LOGIC(vstack[ vstack.length - 1 ]);
	}
	break;
	case 2:
	{
		 rval = vstack[ vstack.length - 3 ] || vstack[ vstack.length - 1 ];
	}
	break;
	case 3:
	{
		 rval = vstack[ vstack.length - 3 ] && vstack[ vstack.length - 1 ];
	}
	break;
	case 4:
	{
		 rval = (isOnlyValidate_ROW_LOGIC? vstack[ vstack.length - 1 ]: !vstack[ vstack.length - 1 ]);
	}
	break;
	case 5:
	{
		 rval = vstack[ vstack.length - 2 ];
	}
	break;
	case 6:
	{
		 rval = checkExpression_ROW_LOGIC(vstack[ vstack.length - 1 ]);
	}
	break;
	case 7:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
	case 8:
	{
		rval = vstack[ vstack.length - 1 ];
	}
	break;
}



			if( ROW_LOGIC_dbg_withparsetree )
				tmptree = new Array();

			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "\tPopping " + pop_tab[act][1] + " off the stack..." );

			for( var i = 0; i < pop_tab[act][1]; i++ )
			{
				if( ROW_LOGIC_dbg_withparsetree )
					tmptree.push( tree.pop() );

				sstack.pop();
				vstack.pop();
			}

			go = -1;
			for( var i = 0; i < goto_tab[sstack[sstack.length-1]].length; i+=2 )
			{
				if( goto_tab[sstack[sstack.length-1]][i] == pop_tab[act][0] )
				{
					go = goto_tab[sstack[sstack.length-1]][i+1];
					break;
				}
			}

			if( ROW_LOGIC_dbg_withparsetree )
			{
				var node = new treenode();
				node.sym = labels[ pop_tab[act][0] ];
				node.att = new String();
				node.child = tmptree.reverse();
				tree.push( treenodes.length );
				treenodes.push( node );
			}

			if( act == 0 )
				break;

			if( ROW_LOGIC_dbg_withtrace )
				__ROW_LOGICdbg_print( "\tPushing non-terminal " + labels[ pop_tab[act][0] ] );

			sstack.push( go );
			vstack.push( rval );
		}
	}

	if( ROW_LOGIC_dbg_withtrace )
		__ROW_LOGICdbg_print( "\nParse complete." );

	if( ROW_LOGIC_dbg_withparsetree )
	{
		if( err_cnt == 0 )
		{
			__ROW_LOGICdbg_print( "\n\n--- Parse tree ---" );
			__ROW_LOGICdbg_parsetree( 0, treenodes, tree );
		}
		else
		{
			__ROW_LOGICdbg_print( "\n\nParse tree cannot be viewed. There where parse errors." );
		}
	}

	return err_cnt;
}


function __ROW_LOGICdbg_parsetree( indent, nodes, tree )
{
	var str = new String();
	for( var i = 0; i < tree.length; i++ )
	{
		str = "";
		for( var j = indent; j > 0; j-- )
			str += "\t";

		str += nodes[ tree[i] ].sym;
		if( nodes[ tree[i] ].att != "" )
			str += " >" + nodes[ tree[i] ].att + "<" ;

		__ROW_LOGICdbg_print( str );
		if( nodes[ tree[i] ].child.length > 0 )
			__ROW_LOGICdbg_parsetree( indent + 1, nodes, nodes[ tree[i] ].child );
	}
}


// BigNumber begin
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/bignumber [rev. #3]

BigNumber = function(n, p, r){
	var o = this, i;
	if(n instanceof BigNumber){
		for(i in {precision: 0, roundType: 0, _s: 0, _f: 0}) o[i] = n[i];
		o._d = n._d.slice();
		return;
	}
	o.precision = isNaN(p = Math.abs(p)) ? BigNumber.defaultPrecision : p;
	o.roundType = isNaN(r = Math.abs(r)) ? BigNumber.defaultRoundType : r;
	o._s = (n += "").charAt(0) == "-";
	o._f = ((n = n.replace(/[^\d.]/g, "").split(".", 2))[0] = n[0].replace(/^0+/, "") || "0").length;
	for(i = (n = o._d = (n.join("") || "0").split("")).length; i; n[--i] = +n[i]);
	o.round();
};
with({$: BigNumber, o: BigNumber.prototype}){
	$.ROUND_HALF_EVEN = ($.ROUND_HALF_DOWN = ($.ROUND_HALF_UP = ($.ROUND_FLOOR = ($.ROUND_CEIL = ($.ROUND_DOWN = ($.ROUND_UP = 0) + 1) + 1) + 1) + 1) + 1) + 1;
	$.defaultPrecision = 5;
	$.defaultRoundType = $.ROUND_HALF_UP;
	o.add = function(n){
		if(this._s != (n = new BigNumber(n))._s) {
      var thisAbs = this.abs();
      var nAbs = n.abs();
      if (thisAbs.compare(nAbs) + 1) {
        var res = thisAbs.subtract(nAbs);
        return res.setSing(this._s);
      } else {
        var res = nAbs.subtract(thisAbs);
        return res.setSing(n._s);
      }
    }
		var o = new BigNumber(this), a = o._d, b = n._d, la = o._f,
		lb = n._f, n = Math.max(la, lb), i, r;
		la != lb && ((lb = la - lb) > 0 ? o._zeroes(b, lb, 1) : o._zeroes(a, -lb, 1));
		i = (la = a.length) == (lb = b.length) ? a.length : ((lb = la - lb) > 0 ? o._zeroes(b, lb) : o._zeroes(a, -lb)).length;
		for(r = 0; i; r = (a[--i] = a[i] + b[i] + r) / 10 >>> 0, a[i] %= 10);
		return r && ++n && a.unshift(r), o._f = n, o.round();
	};
	o.subtract = function(n){
		if(this._s != (n = new BigNumber(n))._s)
			return n._s ^= 1, this.add(n);
		var o = new BigNumber(this), c = o.abs().compare(n.abs()) + 1, a = c ? o : n, b = c ? n : o, la = a._f, lb = b._f, d = la, i, j;
		a = a._d, b = b._d, la != lb && ((lb = la - lb) > 0 ? o._zeroes(b, lb, 1) : o._zeroes(a, -lb, 1));
		for(i = (la = a.length) == (lb = b.length) ? a.length : ((lb = la - lb) > 0 ? o._zeroes(b, lb) : o._zeroes(a, -lb)).length; i;){
			if(a[--i] < b[i]){
				for(j = i; j && !a[--j]; a[j] = 9);
				--a[j], a[i] += 10;
			}
			b[i] = a[i] - b[i];
		}
		return c || (o._s = n._s), o._f = d, o._d = b, o.round();
	};
	o.multiply = function(n){
		var o = new BigNumber(this), r = o._d.length >= (n = new BigNumber(n))._d.length, a = (r ? o : n)._d,
		b = (r ? n : o)._d, la = a.length, lb = b.length, x = new BigNumber, i, j, s;
		for(i = lb; i; r && s.unshift(r), x.set(x.add(new BigNumber(s.join("")))))
			for(s = (new Array(lb - --i)).join("0").split(""), r = 0, j = la; j; r += a[--j] * b[i], s.unshift(r % 10), r = (r / 10) >>> 0);
		return o._f = ((r = la + lb - o._f - n._f) >= (j = (o._d = x._d).length) ? this._zeroes(o._d, r - j + 1, 1).length : j) - r, o.round();
	};
	o.divide = function(n){
		if((n = new BigNumber(n)) == "0")
			throw new Error("Division by 0");
		else if(this == "0")
			return new BigNumber;
		var o = new BigNumber(this), a = o._d, b = n._d, la = a.length - o._f,
		lb = b.length - n._f, r = new BigNumber, i = 0, j, s, l, f = 1, c = 0, e = 0;
		r._s = o._s != n._s, r.precision = Math.max(o.precision, n.precision),
		r._f = +r._d.pop(), la != lb && o._zeroes(la > lb ? b : a, Math.abs(la - lb));
		n._f = b.length, b = n, b._s = false, b = b.round();
		for(n = new BigNumber; a[0] == "0"; a.shift());
		out:
		do{
			for(l = c = 0, n == "0" && (n._d = [], n._f = 0); i < a.length && n.compare(b) == -1; ++i){
				(l = i + 1 == a.length, (!f && ++c > 1 || (e = l && n == "0" && a[i] == "0")))
				&& (r._f == r._d.length && ++r._f, r._d.push(0));
				(a[i] == "0" && n == "0") || (n._d.push(a[i]), ++n._f);
				if(e)
					break out;
				if((l && n.compare(b) == -1 && (r._f == r._d.length && ++r._f, 1)) || (l = 0))
					while(r._d.push(0), n._d.push(0), ++n._f, n.compare(b) == -1);
			}
			if(f = 0, n.compare(b) == -1 && !(l = 0))
				while(l ? r._d.push(0) : l = 1, n._d.push(0), ++n._f, n.compare(b) == -1);
			for(s = new BigNumber, j = 0; n.compare(y = s.add(b)) + 1 && ++j; s.set(y));
			n.set(n.subtract(s)), !l && r._f == r._d.length && ++r._f, r._d.push(j);
		}
		while((i < a.length || n != "0") && (r._d.length - r._f) <= r.precision);
		return r.round();
	};
	o.mod = function(n){
		return this.subtract(this.divide(n).intPart().multiply(n));
	};
	o.pow = function(n){
		var o = new BigNumber(this), i;
		if((n = (new BigNumber(n)).intPart()) == 0) return o.set(1);
		for(i = Math.abs(n); --i; o.set(o.multiply(this)));
		return n < 0 ? o.set((new BigNumber(1)).divide(o)) : o;
	};
	o.set = function(n){
		return this.constructor(n), this;
	};
	o.compare = function(n){
		var a = this, la = this._f, b = new BigNumber(n), lb = b._f, r = [-1, 1], i, l;
		if(a._s != b._s)
			return a._s ? -1 : 1;
		if(la != lb)
			return r[(la > lb) ^ a._s];
		for(la = (a = a._d).length, lb = (b = b._d).length, i = -1, l = Math.min(la, lb); ++i < l;)
			if(a[i] != b[i])
				return r[(a[i] > b[i]) ^ a._s];
		return la != lb ? r[(la > lb) ^ a._s] : 0;
	};
	o.negate = function(){
		var n = new BigNumber(this); return n._s ^= 1, n;
	};
	o.abs = function(){
		var n = new BigNumber(this); return n._s = 0, n;
	};
  o.setSing = function(val) {
    var n = new BigNumber(this); return n._s = val, n;
  };
	o.intPart = function(){
		return new BigNumber((this._s ? "-" : "") + (this._d.slice(0, this._f).join("") || "0"));
	};
	o.valueOf = o.toString = function(){
		var o = this;
		return (o._s ? "-" : "") + (o._d.slice(0, o._f).join("") || "0") + (o._f != o._d.length ? "." + o._d.slice(o._f).join("") : "");
	};
	o._zeroes = function(n, l, t){
		var s = ["push", "unshift"][t || 0];
		for(++l; --l;  n[s](0));
		return n;
	};
	o.round = function(){
		if("_rounding" in this) return this;
		var $ = BigNumber, r = this.roundType, b = this._d, d, p, n, x;
		for(this._rounding = true; this._f > 1 && !b[0]; --this._f, b.shift());
		for(d = this._f, p = this.precision + d, n = b[p]; b.length > d && !b[b.length -1]; b.pop());
		x = (this._s ? "-" : "") + (p - d ? "0." + this._zeroes([], p - d - 1).join("") : "") + 1;
		if(b.length > p){
			n && (r == $.DOWN ? false : r == $.UP ? true : r == $.CEIL ? !this._s
			: r == $.FLOOR ? this._s : r == $.HALF_UP ? n >= 5 : r == $.HALF_DOWN ? n > 5
			: r == $.HALF_EVEN ? n >= 5 && b[p - 1] & 1 : false) && this.add(x);
			b.splice(p, b.length - p);
		}
		return delete this._rounding, this;
	};
}
// BigNumber end
var isValidClickSubmit = false;
var isValidClickBackNext = false;
var isValidInverseSelectGoTo = false;
var isValidClickGo = false;
var tallinn = false;
var goTallinn = true;
var questionForms = [];
var showBeforeAlert = true;
var blurObj = null;
var timeOutForAlerts = new Date().getMilliseconds();
var noScrollBrowser = false;
var scrollToQuestion = null;
var debug = false;
var _current_form = null;
var validationErrorHighliteElements = [];
var validationError3dAllRows = [];
var validationErrorElement = null;
var validationErrorAlert = null;
var isPreviewMode = false;

var selTN = "SELECT";
var inpTN = "INPUT";

var j$ = jQuery.noConflict();
j$.fn.switchClass = function(cOld, cNew) {
  j$(this).removeClass(cOld).addClass(cNew);
};

function scrollToSomeQuestion() {
  var sname = scrollToQuestion;
  if (sname == null || sname.length == 0) return;
  if (sname.charAt(0) == '#') sname = sname.substring(1);
  var elem = document.getElementById(sname);
  if (elem == null) return;
//  var innerSrc = elem.innerHTML;
//  if (innerSrc == null || innerSrc.length == 0) elem.innerHTML = '&nbsp;';
  window.location.hash = sname;
}

function disableShowBeforeAlert() {
  showBeforeAlert = false;
}

function getShowBeforeAlert() {
  return showBeforeAlert;
}

function fillForms() {
  if (document.theForm == null || (questionForms != null && questionForms.length > 0)) return;
  var documentForms = document.forms;
  var documentFormsLength = documentForms.length;
  for (var j = 0; j < documentFormsLength; j++) {
    var currForm = documentForms[j];
    for (var i = 0; i < currForm.length; i++) {
      var elem = currForm[i];
      var qid = findQID(elem.name);
      if (qid <= 0) continue;
      var form = questionForms[qid];
      if (form == null || form.length == 0) {
        form = [];
        questionForms[qid] = form;
      }
      form[form.length] = elem;
    }
  }
}

function findForm(frm_name) {
  if (questionForms.length == 0) {
    fillForms();
  }
  var index = 0;
  var questionString = "Question";
  if (frm_name.indexOf(questionString) == 0) index = parseInt(frm_name.substring(questionString.length));
  isNaN(index) && alert("findForm(" + frm_name + "),\n index==isNaN <= " + frm_name.substring(questionString.length));
  var arr = questionForms[index];
  return (arr == null || arr.length == 0) ? [] : arr;
}

function openLink(uri) {
  if (uri != null && uri.length > 0) {
    var windowname = "new" + (Math.round(Math.random() * 1000000));
    OpenWindow = window.open(uri, windowname, '');
    OpenWindow.focus();
  }
}

function removeLeadingZeroes(text) {
  text = "" + text;
  text = j$.trim(text); //text.replace(/^\s+/, '').replace(/\s+$/, ''); //  text=text.trim();

  var negative = (text.indexOf("-") == 0);
  while (text.indexOf("-") == 0) {
    text = text.substring(1);
  }
  if (text != null && text.length > 0) {
    if (text.search("^0+$") == 0) return "0";
    var result = text.replace(/^(0+)(.*)$/, "$2");
    if (result == null || result.length == 0) return "0";

    if (result.indexOf(".") == 0) result = "0" + result;
    if (negative) result = "-" + result;
    if (result == 0) result = "0";
    return result;
  }
  return (negative) ? "0" : "";
}

function transform(sometext) {
  var i = 0;
  var transformedtext = "";
  if (sometext != null && sometext.length > 0) {
    while (i < sometext.length) {
      if (sometext.charCodeAt(i) == 39) transformedtext += "&#39;";
      else if (sometext.charCodeAt(i) == 38) transformedtext += "&#38;";
      else transformedtext += sometext.charAt(i);
      i++;
    }
  }
  return transformedtext;
}

function findQID(name) {
  if (name == null || name.length == 0) return "0";
  var qid = name.replace(/(R|other|total)(\d+)(_\d+(_\d+)?)?/, "$2");
  var intQID = parseInt(qid);
  if (isNaN(intQID)) return 0;
  return intQID;
}

function findAID(name) {
  if (name == null || name.length == 0) return 0;
  var aid = name.replace(/[a-z]+\d+(_(\d+)(_\d+)?)?/i, "$2");
  var intAID = parseInt(aid);
  if (isNaN(intAID)) return 0;
  return intAID;
}

function moveRadio(form_name, name, value, fromOther, isRadio, obj) {
  if (name != null && value != null) {
    var i = 0;
    var frm = findForm(form_name);
    while (i < frm.length) {
      var frmElem = frm[i];
      if (obj != null && frmElem.form.name != obj.form.name) {
        i++;
        continue;
      }
      if (frmElem != null &&
          frmElem.name != null &&
          frmElem.name.indexOf(name) == 0 &&
          frmElem.value == value &&
          (obj == null || frmElem.form.name == obj.form.name)) {
        if (!isRadio && frmElem.checked) {
          if (debug) alert('moveRadio=checked.false');
          frmElem.checked = false;
        } else {
          if (debug) alert('moveRadio=checked.true');
          frmElem.checked = true;
        }
        if (fromOther) {
          if (debug) alert('moveRadio=checked.true');
          frmElem.checked = true;
        }
      }
      i++;
    }
  }
}

var formQuestions = [];

function fillFormQuestions() {
  if (formQuestions["theForm"] != null) return;// cache already filled
  var documentForms = document.forms;
  //fill general section questions elements
  var generalFormQuestions = [];
  fillFormQuestionsArrayByForm(documentForms[0], generalFormQuestions);
  formQuestions[documentForms[0].name] = generalFormQuestions;

  //fill subject sections questions elements
  for (var i = 1; i < documentForms.length; i++) {
    var subjectFormQuestions = [];
    fillFormQuestionsArrayByForm(documentForms[i], subjectFormQuestions);
    formQuestions[documentForms[i].name] = subjectFormQuestions;
  }
}

function fillFormQuestionsArrayByForm(form, array) {
  var elems = form.elements;
  for (var i = 0; i < elems.length; i++) {
    var foundQid = findQID(elems[i].name);
    if (!isNaN(foundQid) && foundQid > 0) {
      var questionElements = array[foundQid];
      if (questionElements == null) questionElements = [];
      questionElements.push(elems[i]);
      array[foundQid] = questionElements;
    }
  }
}

function findQuestionElementsOnForm(QID, currentForm) {
  fillFormQuestions();
  var formName;
  if (currentForm == null) {//general section
    formName = "theForm";
  } else {
    formName = currentForm.name;
  }
  var questionsArray = formQuestions[formName];
  if (questionsArray == null) {
    return [];
  } else {
    if (questionsArray[QID] == null) return [];
    return questionsArray[QID];
  }
}

function validateOtherState(QID, qtext) {
  //var frm = findForm('Question' + QID);
  var frm = findQuestionElementsOnForm(QID, _current_form);

  var AID = 0;
  var elementOther;
  var elementsExceptOther = [];
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    var answerId;
    if (elem.name.indexOf("other" + QID) == 0) {
      answerId = findAID(elem.name);
      if (isNaN(answerId) || answerId <= 0) continue;
      AID = answerId;
      elementOther = elem;
    } else {
      answerId = elem.value;
      elementsExceptOther[answerId] = elem;
    }
  }

  if (elementOther != null && elementOther.value.length == 0) {
    var elementNearOther = elementsExceptOther[AID];
    if (elementNearOther != null && elementNearOther.checked) {
      beforeSubmitErrorAlert(qtext, elementOther, QID);
      return false;
    }
  }

  return true;
}

function validateDependent3DMatrix(QID, qtext, isRequired, isPreferred, hasQText) {
  if (isRequired) {
    if (!validateRequiredGeneral(QID, qtext, hasQText)) return false;
  }
  var i = 0;
  var frm = findQuestionElementsOnForm(QID, _current_form);
  var arr = new Object();
  var hasAnyAnsweredRow = false;
  for (i = frm.length - 1; i >= 0; i -= 1) {
    var elem = frm[i];
    if (elem == null) break;
    var ename = elem.name;
    if (ename == null) break;

    var enameUpperCase = ename.toUpperCase();
    var elemTagName = elem.tagName;
    var rowAnswered = elemTagName != null &&
                      (elemTagName.toUpperCase().indexOf(inpTN) >= 0 &&
                       (enameUpperCase.indexOf("CHECK") >= 0 ||
                        enameUpperCase.indexOf("RADIO") >= 0) && elem.checked ||
                       elemTagName.toUpperCase().indexOf(selTN) >= 0 && elem.selectedIndex > 0 ||
                       enameUpperCase.indexOf("OTHER") >= 0 &&
                       enameUpperCase.indexOf("CHECK") < 0 &&
                       enameUpperCase.indexOf("RADIO") < 0 &&
                       elem.value != null && elem.value.length > 0);

    var getAnswerVar = getAnswer(ename);
    if (arr[getAnswerVar] == null) {
      arr[getAnswerVar] = rowAnswered;
    } else if (rowAnswered) {
      arr[getAnswerVar] = rowAnswered;
    }
    if (rowAnswered) hasAnyAnsweredRow = true;
  }

  if (!hasAnyAnsweredRow && !isRequired) return true;

  for (var key in arr) {
    if (!arr[key]) {
      pleaseAnswerAllRowsErrorAlert(hasQText, qtext, elem, QID);
      return false;
    }
  }
  return true;
}

function addElementForHighlite3dMatrixAllRows(form, QID) {
  var highliteTdElement = findElementForHiglite(form, QID);
  if (highliteTdElement != null) validationError3dAllRows.push(highliteTdElement);
}

function getAnswer(text) {
  return text.replace(/other\d+_(\d+)(_.*)?/i, '$1');
}

function checkMandatoryAnswersNormal(qid, aids, aTexts) {
  var result = false;
  for (var i = 0; i < aids.length; i++) {
    result |= !checkMandatoryAnswered(qid, aids[i]);
  }
  result && reactionOnMandatoryAnswerError(qid, aTexts);
  return result;
}

function checkMandatoryAnswers360Internal(formsContext, qid, aids, aTexts) {
  var result = false;
  for (var i = 0; i < aids.length; i++) {
    var answered = true;
    formsContext.each(function() {
      answered &= checkMandatoryAnswered(qid, aids[i], j$(this));
    });
    result |= !answered;
  }
  result && reactionOnMandatoryAnswerError(qid, aTexts);
  return result;
}
function checkMandatoryAnswers360(formsContext, qid, aids, aTexts) {
  return isQuestionInGeneralSection(qid)
      ? checkMandatoryAnswers360Internal(j$("[name='theForm']"), qid, aids, aTexts)
      : checkMandatoryAnswers360Internal(formsContext, qid, aids, aTexts)
}

function checkMandatoryAnswers(qid, aids, aTexts) {
  var trForms = j$("tr[id^='trForm']");
  return trForms.length
      ? checkMandatoryAnswers360(trForms, qid, aids, aTexts)
      : checkMandatoryAnswersNormal(qid, aids, aTexts);
}

function checkMandatoryAnswered(qid, aid, context) {
  var answered = false;
  var jAnswer = context
      ? j$("[name*='" + qid + "_" + aid + "']", context)
      : j$("[name*='" + qid + "_" + aid + "']");
  jAnswer.each(function() {
    var jThis = j$(this);
    var tagName = this.tagName.toUpperCase();
    if (tagName == selTN) {
      answered |= (j$.trim(jThis.val()).length > 0);
    } else {
      var type = jThis.attr("type").toLowerCase();
      if (type == "radio" || type == "checkbox") {
        answered |= (jThis.is(":checked"));
      } else {
        answered |= (j$.trim(jThis.val()).length > 0);
      }
    }
  });
  var jAnswerTr = context 
      ? j$("#AnswerTr" + qid + "_" + aid, context)
      : j$("#AnswerTr" + qid + "_" + aid);
  return markupMandatoryAnswer(jAnswerTr, answered);
}

function markupMandatoryAnswer(jElem, answerState) {
  if (answerState) {
    jElem.switchClass("MandatoryAnswerError", "MandatoryAnswerNormal");
  } else {
    jElem.switchClass("MandatoryAnswerNormal", "MandatoryAnswerError");
  }
  return answerState;
}

function checkMustAnswerAllFields3D(qid, aids, qtext) {
  var trForms = j$("tr[id^='trForm']");
  if (trForms.length) {
    var answered = true;
      trForms.each(function() {
        answered &= checkAnsweredAllFields3DFull(qid, aids);
      });
      if (!answered) {
        reactionOnErrorMustAnswerAllFields3D(qid, qtext);
        return true;
      }
  } else {
    if (!checkAnsweredAllFields3DFull(qid, aids)) {
      reactionOnErrorMustAnswerAllFields3D(qid, qtext);
      return true;
    }
  }
  return false;
}

function checkAnsweredAllFields3DFull(qid, aids) {
  var res = true;
  for (var i = 0; i < aids.length; i++) {
    res &= checkAnsweredAllFields3D(j$("[name*='" + qid + "_" + aids[i] + "']"));
  }
  return res;
}

function checkAnsweredAllFields3D(jAnswer) {
  var answered = true;
  var answeredPickOne = false;
  var hasPickOne = false;
  var jPickOneParents = [];
  jAnswer.each(function() {
    var jThis = j$(this);
    var jParent = j$(this.parentNode);
    var tagName = this.tagName.toUpperCase();
    if (tagName == selTN) {
      answered &= markupMustAnswerAllFields3D(jParent, (j$.trim(jThis.val()).length > 0));
    } else {
      var type = jThis.attr("type").toLowerCase();
      if (type == "radio") {
        hasPickOne = true;
        jPickOneParents.push(jParent);
        answeredPickOne |= jThis.is(":checked");
      } else {
        answered &= markupMustAnswerAllFields3D(jParent, (j$.trim(jThis.val()).length > 0));
      }
    }
  });
  if (hasPickOne) {
    answered &= markupMustAnswerAllFields3DPickOne(jPickOneParents, answeredPickOne);
  }
  return answered;
}

function markupMustAnswerAllFields3DPickOne(jParents, answerState) {
  j$.each(jParents, function(){
    markupMustAnswerAllFields3D(this, answerState);
  });
  return answerState;
}

function markupMustAnswerAllFields3D(jParentElem, answerState) {
  if (answerState) {
//    jParentElem.removeClass("MustAnswerAllFields3DError").addClass("MustAnswerAllFields3DNormal");
    jParentElem.switchClass("MustAnswerAllFields3DError", "MustAnswerAllFields3DNormal");
  } else {
//    jParentElem.removeClass("MustAnswerAllFields3DNormal").addClass("MustAnswerAllFields3DError");
    jParentElem.switchClass("MustAnswerAllFields3DNormal", "MustAnswerAllFields3DError");
  }
  return answerState;
}

function validateRequiredGeneral(QID, qtext, hasQText, answerRequiredCondition) {
  //if validate main form, but question from subject's forms, OR vice versa
  if (!isQuestionExistInForm(QID, _current_form)) {
    return true;
  }
  var isMustAnswerConditional = answerRequiredCondition != null && answerRequiredCondition.length > 0;
  if (!isMustAnswerConditional && validateRequiredGeneralSilent(QID)) {
    return true;
  } else if (isMustAnswerConditional) {
    if (validateRequiredConditional(answerRequiredCondition)) {
      if (validateRequiredGeneralSilent(QID)) {//need to check current question was answered
        return true;
      }
    } else {//if condition doesn't fit, then no need to check question was answered or not for current question
      return true;
    }
  }
  reactionOnError(QID, qtext);
  return false;
}

function addElementForHighlite(form, QID) {
  var highliteTdElement = findElementForHiglite(form, QID);
  if (highliteTdElement != null) validationErrorHighliteElements.push(highliteTdElement);
}

//if validate main form, but question from subject's forms, OR vice versa
function isQuestionExistInForm(QID, form) {
  return findQuestionElementsOnForm(QID, _current_form).length > 0;
}

function findElementForHiglite(form, QID) {
  var formId = form.name.substr(7);
  if (formId == null || isNaN(formId)) return null;
  var posibleElementIds = [];
  posibleElementIds.push("tdAnswersCellForm" + formId + "Id" + QID);//matrix view
  posibleElementIds.push("questionMainTableId" + QID + "_Form" + formId);//one subject per page
  posibleElementIds.push("QuestionAnswersTableId" + QID + "_Form" + formId);//one subject per page compare question
  for (var i = 0; i < posibleElementIds.length; i++) {
    var highliteElement = document.getElementById(posibleElementIds[i]);
    if (highliteElement != null) {
      return highliteElement;
    }
  }
}

function validateRequiredConditional(answerRequiredCondition) {
  return parseExpressionLogic_ROW_LOGIC(answerRequiredCondition, false);
}

function validateRequiredGeneralSilent(QID) {
  var frm = findQuestionElementsOnForm(QID, _current_form);
  var i = frm.length;
  while (i >= 0) {
    i -= 1;
    var elem = frm[i];

    if (elem == null) break;
    var ename = elem.name;
    if (ename == null) break;
    if (ename.indexOf("R" + QID) == 0) {
      focus_obj = elem;
      if (elem.value != 0 && elem.checked) {
        return true;
      }
      if (elem.selectedIndex > 0) {
        return true;
      }
      for (ii = 1; elem.options != null && ii < elem.options.length; ii++) {
        if (elem.options[ii].selected) {
          return true;
        }
      }
      if (elem.tagName != null &&
          elem.tagName.toUpperCase().indexOf(selTN) >= 0 &&
          parseInt(elem.value, 10) > 0) {
        return true;
      }
    } else if (ename.indexOf("other" + QID) == 0) {
      if (ename.search(/radio|check/) >= 0) {
        if (frm[i].checked) {
          return true;
        }
      } else {
        if (frm[i].value != null && frm[i].value.length > 0) {
          return true;
        }
        if (elem.tagName != null &&
            elem.tagName.toUpperCase().indexOf(selTN) >= 0 &&
            elem.selectedIndex > 0) {
          return true;
        }
      }
    }
  }
  return false;
}

function validateRequiredElement(QID, AID, columnNum, matchResult) {
  QID = parseInt(QID);
  AID = parseInt(AID);
  columnNum = parseInt(columnNum);
  if (isNaN(QID)) QID = null;
  if (isNaN(AID)) AID = null;
  if (isNaN(columnNum)) columnNum = null;
  if (matchResult == "") matchResult = null;
  var frm = findQuestionElementsOnForm(QID, _current_form);
  if (_current_form != null && frm != null && frm.length == 0) frm = findQuestionElementsOnForm(QID, null); // condition has questions from general section
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    if (elem == null) {
      continue;
    }
    //for multi forms pages, like matrix view for survey 360, but questions from condition can be owned by main form (general section)
    //and so we should validate elements from main form, not only from specified form
    var ename = elem.name;
    if (ename == null) break;
    //total answer
    if (AID != null &&
        ename.indexOf("total" + QID) == 0 &&
        elem.id.substring(("inputtextother" + QID).length + 1).indexOf(AID) >= 0) {
      return elem.value != null && elem.value.length > 0 && (matchResult == null || validateTextResult(matchResult, elem.value));
    }
    else if (ename.indexOf("R" + QID) == 0 && matchResult == null) {
      focus_obj = elem;
      //drop dawn, list
      if (elem.tagName != null && elem.tagName.toUpperCase().indexOf(selTN) >= 0) {
        if (elem.multiple == true) {//list box
          var optionsList = elem.options;
          for (var ii = 1; ii < optionsList.length; ii++) {//begins from 1, skip the first raw "Please select one or more..."
            var option = optionsList[ii];
            if (option.selected && (option.value == AID || AID == null)) return true;
          }
        } else if (elem.value == AID || (AID == null && elem.selectedIndex > 0))//drop down
          return true;
      }
      if (elem.value == AID ||
          (AID == null && ename.substring(("R" + QID).length + 1).length == 0)) {//check all, radio
        //if element is hidden, then this question was answered on previous page
        if (elem.checked || (elem.tagName.toUpperCase() == inpTN && elem.type == 'hidden')) return true;
        // continue in case of compare one by one
      }
      if (ename.substring(("R" + QID).length + 1) == AID ||
          (AID == null && ename.substring(("R" + QID).length + 1).length > 0)) {//rank grid
        //rank grid
        if (columnNum != null &&
            ( (AID != null && (parseInt(elem.value) - 1) == columnNum)//Q1.A1.C1
                || (AID == null && (parseInt(elem.value) - 1) ==
                                   getIndexByColumnId(columnNum)))) {//Q1.C1 - in this case columnNum is id of a column
          //if element is hidden, then this question was answered on previous page
          if (elem.checked || (elem.tagName.toUpperCase() == inpTN && elem.type == 'hidden'))
            return true;
          //continue for cases like Q1.C1 (seek for first checked answer in current column)
        }
        //find first voted answer in rank grid question, but without concrete column number, i.e. Q1.A2 (without .C1)
        else if (columnNum == null &&
                 ( elem.checked || (elem.tagName.toUpperCase() == inpTN && elem.type == 'hidden') )) {
          return true;
        }
      }
    }
    else if (ename.indexOf("other" + QID) == 0) {//3d and text inputs
      if (ename.search(/radio|check/) >= 0) {
        if (AID == null || ename.substring(("other" + QID).length + 1).indexOf(AID) >= 0) {
          if ((columnNum != null &&
               ((AID != null && elem.value == columnNum) || //Q1.A2.C3
                (AID == null && elem.value == getIndexByColumnId(columnNum))) ) //Q1.C3
            //if validate only the row, without concrete column number
              || columnNum == null) {
            if (elem.checked ||
              //if element is hidden, then this question was answered on previous page
                (elem.tagName.toUpperCase() == inpTN && elem.type == 'hidden')) return true;
            //else continue to find first voted(if exist) in case of only row validation, without concrete column
          }
        }
      } else {
        if ((columnNum != null && ename.substring(("other" + QID).length + 1) == (AID + "_" + columnNum)) ||
          //if validate only the column, without concrete answer id
            (columnNum != null && AID == null &&
             ename.substring(("other" + QID).length + 1).indexOf("_" + getIndexByColumnId(columnNum)) >= 0) ||
          //if validate only the row, without concrete column number
            (columnNum == null && ename.substring(("other" + QID).length + 1).indexOf(AID) >= 0) ||
          //if validate only the question, without concrete column number and answerId
            (columnNum == null && AID == null)) {

          if (elem.tagName != null && elem.tagName.toUpperCase().indexOf(selTN) >= 0) {
            if (elem.selectedIndex > 0) return true;
            //else continue to find first voted(if exist) in case of only row validation, without concrete column
          }
          else {
            if (((elem.value != null && elem.value.length > 0)
              //if element is hidden, then this question was answered on previous page
                || (elem.tagName.toUpperCase() == inpTN && elem.type == 'hidden')) &&
              //for text answer
                (matchResult == null || validateTextResult(matchResult, elem.value))) {
              return true;
            }
            //else continue to find first voted(if exist) in case of only row validation, without concrete column
          }
        }
      }
    }
  }
  return false;
}

function validateTextResult(condition, result) {
  var conditionValue = condition.substring(2, condition.length);
  var isMatches = getResultForMatches(conditionValue, result);
  if (condition.indexOf("==") == 0) {
    return isMatches;
  }
  if (condition.indexOf("<>") == 0 ||
      condition.indexOf("!=") == 0) {
    return !isMatches;
  }
  return false;
}

function getResultForMatches(condition, result) {
  var condUpperCase = condition.toUpperCase();
  if (condUpperCase.indexOf("LIKE") == 0) {
    return result.trim().indexOf(condition.replace("LIKE", "")) >= 0;
  } else if (condUpperCase.indexOf("RMATCHES") == 0) {
    var matchingText = result.trim().match(condition.replace("RMATCHES", ""));
    return matchingText != null && matchingText[0] == result;
  } else if (condUpperCase.indexOf("RLIKE") == 0) {
    return result.trim().search(condition.replace("RLIKE", "")) >= 0;
  }
  return condition == result.trim();
}

function checkPreferredCompareMatrix(QID, qtext, isRequired, isPreferred, total_lines, hasQText, answerRequiredCondition) {
  if (_current_form != null && validationErrorElement != null) {//in multi forms only one alert should be shown
    return true;
  }
  if (isRequired) {
    if (!validateRequiredGeneral(QID, qtext, hasQText, answerRequiredCondition)) return false;
  }
  var k = 0;
  var frm = findQuestionElementsOnForm(QID, _current_form);
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    if (elem == null || elem.name == null) continue;
    if (elem.name.indexOf("R" + QID + "_") >= 0) {
      if (elem.checked) {
        k++;
      }
    }
  }
  if (k == total_lines || k == 0) return true;
  pleaseAnswerErrorAlert(qtext, QID);
  return false;
}

function checkCheckboxes(QID, qtext, isRequired, isPreferred, minRequired, maxAllowed, exclusiveAID, hasQText, answerRequiredCondition) {
  if (_current_form != null && validationErrorElement != null) {//in multi forms only one alert should be shown
    return true;
  }
  if (exclusiveAID > 0) {
    var exclusiveAnswered = false;
    var nonExclusiveAnsweredCount = 0;
    var exclusiveElementPos = -1;
    var frm = findQuestionElementsOnForm(QID, _current_form);
    for (var j = 0; j < frm.length; j++) {
      var elem = frm[j];
      if (elem != null && elem.type == "checkbox" && elem.name.indexOf("R" + QID) == 0 && elem.value == exclusiveAID) {
        if (elem.checked) exclusiveAnswered = true;
        exclusiveElementPos = j;
      } else if (elem != null && elem.type == "checkbox" && elem.name.indexOf("R" + QID) == 0 && elem.value != exclusiveAID) {
        if (elem.checked) nonExclusiveAnsweredCount++;
      }
    }
    if (exclusiveAnswered && nonExclusiveAnsweredCount > 0) {
      alertExclusive(qtext);
      scrollToQuestion = '#Q' + QID;
      window.setTimeout(scrollToSomeQuestion, 250);
      return false;
    }
  }
  if (isPreferred && validateRequiredGeneralSilent(QID)) removeFromPreferredArrays(QID);
  if (isRequired) {
    if (!validateRequiredGeneral(QID, qtext, hasQText, answerRequiredCondition)) return false;
  }
  if (maxAllowed == 0 && minRequired <= 1) return true;
  var count = getCountCheckedCheckboxes(QID, _current_form);
  if ((count <= maxAllowed || maxAllowed == 0) && (count == 0 || count >= minRequired)) return true;
  alertMinMaxReq(QID, qtext, minRequired, maxAllowed, _current_form);
  return false;
}

function getCountCheckedCheckboxes(QID, currentForm) {
  var count = 0;
  var frm = findQuestionElementsOnForm(QID, currentForm);
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    if (elem == null) continue;
    var ename = elem.name;
    if (ename == null) continue;
    if (ename.indexOf("R" + QID) == 0) {
      if (elem.value != 0 && elem.checked) {
        count++;
      }
    }
  }
  return count;
}

function getCountCheckedInListbox(QID, currentForm) {
  var count = 0;
  var frm = findQuestionElementsOnForm(QID, currentForm);
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    if (elem == null) continue;
    var ename = elem.name;
    if (ename == null) continue;
    if (ename.indexOf("R" + QID) == 0) {
      var opts = elem.options;
      for (var j = 1; j < opts.length; j++) {
        if (opts[j].selected) count++;
      }
    }
  }
  return count;
}

function checkListbox(QID, qtext, isRequired, isPreferred, minRequired, maxAllowed, hasQText, answerRequiredCondition) {
  if (_current_form != null && validationErrorElement != null) {//in multi forms only one alert should be shown
    return true;
  }
  if (isRequired) {
    if (!validateRequiredGeneral(QID, qtext, hasQText, answerRequiredCondition)) return false;
  }
  if (maxAllowed == 0 && minRequired <= 1) return true;
  var count = getCountCheckedInListbox(QID, _current_form);
  if ((count <= maxAllowed || maxAllowed == 0) && (count == 0 || count >= minRequired)) return true;
  alertMinMaxReq(QID, qtext, minRequired, maxAllowed, _current_form);
  return false;
}

function fillArray(frm) {
  var retArray = [];
  var count = 1;
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    if (elem != null && elem.name != null && elem.name.indexOf('other') == 0 && (frm[i].type.toUpperCase()) != 'HIDDEN') {
      retArray[count] = elem;
      count++;
    }
  }
  retArray[0] = 0;
  return retArray;
}

function getTotalElement(frm, currentForm) {
  for (var i = 0; i < frm.length; i++) {
    var elem = frm[i];
    if (elem != null && elem.name != null && elem.name.indexOf('total') == 0) {
      if (currentForm == null || currentForm.name == elem.form.name) {
        return frm[i];
      }
    }
  }
  return null;
}

function checkvalue(focusObj, alert_on, preffix, suffix, decimal_place, decimal_divider, thousend_divider) {
  var value = subStringInteger(focusObj.value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  if (value.length == 0 || isNaN(parseInt(value, 10))) {
    if (alert_on) focusObj.focus();
    return false;
  }
  return true;
}

function fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider) {
  value = "" + removeLeadingZeroes(value);
  var stopSignal = false;
  if (value.charAt(0) == '0') {
    var res = "";
    var stopSignal = false;
    var i = 0;
    var decimalDividerFirstChar = decimal_divider.charAt(0);
    while (i < value.length) {
      if (stopSignal) {
        res += value.charAt(i);
      } else {
        if (value.charAt(i) != '0' || value.charAt(i + 1) == decimalDividerFirstChar) {
          stopSignal = true;
          res += value.charAt(i);
        }
      }
      i++;
    }
    value = res;
  }
  var foundDot = value.indexOf(decimal_divider);
  if (foundDot < 0) {
    var i = 0;
    if (decimal_place >= 0) value += decimal_divider;
    while (i < decimal_place) {
      value += "0";
      i++;
    }
  } else {
    var i = 0;
    var len = value.length - foundDot;
    while (len + i <= decimal_place) {
      value += "0";
      i++;
    }
  }
  var negativeValue = value.indexOf("-") >= 0;
  var i = value.indexOf(decimal_divider) - 1;
  var res = "";
  var j = 0;
  while (i >= 0) {
    if (j == 3 && negativeValue && i > 0 ||
        j == 3 && !negativeValue) {
      /*if (preffix.indexOf("$")>=0)*/
      res += thousend_divider;
      j = 0;
    }
    j++;
    res += value.charAt(i);
    i -= 1;
  }
  var dotIdx = value.indexOf(decimal_divider);
  var suf = value.substring(dotIdx + 1, dotIdx + 1 + decimal_place);
  value = "";
  i = res.length - 1;
  while (i >= 0) {
    value += res.charAt(i);
    i -= 1;
  }
  if (value.length == 0) value = "0";
  if (decimal_place > 0) value += decimal_divider + suf;
  var result = value;
  if (preffix.length > 0) result = preffix + " " + value;
  if (suffix.length > 0) result += " " + suffix;
  return result;
}

function intvalue(focusObj, dontFill, value_obj, preffix, suffix, decimal_place, decimal_divider, thousend_divider) {
  if (focusObj != null && focusObj != window && value_obj.form.name != focusObj.form.name) return 0;
  var value = subStringInteger(value_obj.value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  if (!dontFill && value_obj == focusObj && value_obj.value != null && value_obj.value.length > 0) {
    value_obj.value = fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  }
  var res = parseFloat(value);
  if (isNaN(res)) value = 0;
  if (!dontFill && value_obj.value != null && value_obj.value.length > 0) {
    value_obj.value = fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  }
  return value;
}

function removeDecimal(value, decimal_place, decimal_divider) {
  var res = value;
  var decimalIndex = value.indexOf(decimal_divider);
  if (decimalIndex > 0) {
    var cutIndex = decimalIndex + decimal_place + ((decimal_place > 0) ? 1 : 0);
    res = value.substring(0, cutIndex);
  }
  return res;
}

function appendZeroes(value, decimal_place, decimal_divider) {
  var idx = value.indexOf(decimal_divider);
  while (idx > 0 && value.length - idx <= decimal_place) value += "0";
  return value;
}

function removePreffix(value, preffix) {
  if (preffix.length > 0) {
    var idx = value.indexOf(preffix);
    if (idx >= 0) value = value.substring(idx + preffix.length, value.length);
  }
  return value;
}

function removeSuffix(value, suffix)
{
  if (value == null || value.length == 0) return value;
  if (value.indexOf(suffix) > 0) return value.substring(0, value.indexOf(suffix));
  return value;
}

function removeNaNs(value, decimal_divider, thousend_divider) {
  var regexp = new RegExp("[^-0-9" + decimal_divider.charAt(0) + "]+", "gi");
  return value.replace(regexp, "");
}

function extractNumbers(value, decimal_divider) {
  var i = 0;
  var res = "";
  while (i < value.length) {
    if (value.charAt(i) == decimal_divider.charAt(0) ||
        value.charAt(i) == '-' && i == 0 ||
        !isNaN(parseInt(value.charAt(i), 10))) res += value.charAt(i);
    i++;
  }
  return res;
}

function normalizeNumber(value, decimal_place, decimal_divider) {
  if (value.length == 0) value = "0";
  var indexOfDecDiv = value.indexOf(decimal_divider);
  if (indexOfDecDiv == 0) {
    value = "0" + value;
    indexOfDecDiv++;
  }
  if (indexOfDecDiv >= 0) {
    var begin = value.substring(0, indexOfDecDiv);
    var end = value.substring(indexOfDecDiv + 1);
    if (end.length > decimal_place) {
      end = end.substring(0, decimal_place);
    }
    while (end.length < decimal_place) {
      end += "0";
    }
    value = begin + decimal_divider + end;
  } else {
    if (decimal_place > 0) value += decimal_divider;
    while (decimal_place > 0) {
      value += "0";
      decimal_place--;
    }
  }
  return value;
}

function removeSpaces(value) {
  return value.replace(/\s+/g, "");
}

function subStringAsInteger(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider) {
  var ret = removeSpaces(value);
  value = removeSuffix(ret, suffix);
  value = appendZeroes(value, decimal_place, decimal_divider);
  value = removeDecimal(value, decimal_place, decimal_divider);
  value = removePreffix(value, preffix);
  value = removeLeadingZeroes(value);
  return value;
}

function subStringInteger(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider) {
  value = subStringAsInteger(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  if (value == null || value.length == 0) return "";
  value = removeNaNs(value, decimal_divider, thousend_divider);
  value = extractNumbers(value, decimal_divider);
  value = normalizeNumber(value, decimal_place, decimal_divider);
  return value;
}

function checkSum1(focusObj, fromBody, output_alert, qtext, QID, total_min, total_max, answer_required, preffix, suffix,
                   decimal_place, decimal_divider, thousend_divider) {
  if (_current_form != null && validationErrorElement != null) {//in multi forms only one alert should be shown
    return true;
  }
  var currentForm = (focusObj == null || focusObj == window)
          ? _current_form
          : focusObj.form;
  var foundForm = findQuestionElementsOnForm(QID, currentForm);
  if (foundForm.length == 0) return true;
  var checkArray1 = fillArray(foundForm);
  var totalElement1 = getTotalElement(foundForm, currentForm);
  if (isNaN(checkArray1.length)) return true;
  var empty1 = 1;
  var i1 = 1;
  while (i1 < checkArray1.length) {
    var el = checkArray1[i1];
    if (el != null) {
      if (el.value == "") empty1++;
    }
    i1++;
  }
  if (empty1 == checkArray1.length) {// if all fields empty
    totalElement1.value = "";
    return true;
  }
  return checkSum(focusObj, fromBody, output_alert, qtext, QID, total_min, total_max, answer_required, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
}

function onunloadSaving(onsubmit, onbefore) {
  if (document.theForm == null) return false;
  var hasData = false;
  for (var i = 0; i < document.theForm.elements.length; i++) {
    var elem = document.theForm.elements[i];
    if (elem.value != null || elem.selectedIndex > 0) {
      if (elem.value != null && elem.name.indexOf("other") >= 0 && elem.value.length > 0) {
        hasData = true;
        break;
      }
    }
    if (elem.name.indexOf("other") >= 0) continue;
    if (elem.value != null && elem.checked) {
      hasData = true;
      break;
    } else {
      if (elem.selectedIndex > 0) {
        hasData = true;
        break;
      }
    }
  }
  return false;
}

function removeFromPreferredArrays(QID) {
  if (QID <= 0) return;
  var i = 0;
  while (i < prefAnsweredQue.length) {
    var prefAnsweredQueOldValue = prefAnsweredQue[i];
    if (prefAnsweredQueOldValue == QID && prefAnsweredQueOldValue > 0) {
      prefAnsweredQueBackup[i] = prefAnsweredQueOldValue;
      prefAnsweredQueTextsBackup[i] = prefAnsweredQueTexts[i];
      prefAnsweredQue[i] = 0;
      prefAnsweredQueTexts[i] = "";
    }
    i++;
  }
}

function addToPreferredArrays(QID) {
  if (QID <= 0) return;
  var i = 0;
  while (i < prefAnsweredQue.length) {
    if (prefAnsweredQueBackup[i] == QID) {
      prefAnsweredQue[i] = prefAnsweredQueBackup[i];
      prefAnsweredQueTexts[i] = prefAnsweredQueTextsBackup[i];
      prefAnsweredQueBackup[i] = 0;
      prefAnsweredQueTextsBackup[i] = "";
    }
    i++;
  }
}

var err_flg = false;

function subStringIntegerWithAlert(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider, msg, ba) {
  value = subStringAsInteger(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  if (value == null || value.length == 0) return "";
  value = removeNaNs(value, decimal_divider, thousend_divider);
  value = extractNumbers(value, decimal_divider);
  value = normalizeNumber(value, decimal_place, decimal_divider);
  return value;
}

function intvalueWithAlert(focusObj, dontFill, value_obj, preffix, suffix, decimal_place, decimal_divider, thousend_divider, msg) {
  var value = subStringIntegerWithAlert(value_obj.value, preffix, suffix, decimal_place, decimal_divider, thousend_divider, msg, false);
  if (!dontFill && value_obj == focusObj && value_obj.value != null && value_obj.value.length > 0) {
    value_obj.value = fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  }
  var res = parseFloat(value);
  if (isNaN(res)) value = 0;
  if (!dontFill && value_obj.value != null && value_obj.value.length > 0) {
    value_obj.value = fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  }
  return value;
}

function subStringIntegerWithErrorCode(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider, err_code) {
  value = subStringAsInteger(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  if (value == null || value.length == 0) return "";
  var regexp_ch = new RegExp("[^-0-9" + decimal_divider.charAt(0) + thousend_divider.charAt(0) + "]+", "gi");
  err_flg = regexp_ch.test(value);
  value = removeNaNs(value, decimal_divider, thousend_divider);
  value = extractNumbers(value, decimal_divider);
  value = normalizeNumber(value, decimal_place, decimal_divider);
  return value;
}

function intvalueWithErrorCode(focusObj, dontFill, value_obj, preffix, suffix, decimal_place, decimal_divider, thousend_divider, err_code) {
  var value = subStringIntegerWithErrorCode(value_obj.value, preffix, suffix, decimal_place, decimal_divider, thousend_divider, err_code);
  if (!dontFill && value_obj == focusObj && value_obj.value != null && value_obj.value.length > 0) {
    value_obj.value = fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  }
  var res = parseFloat(value);
  if (isNaN(res)) value = 0;
  if (!dontFill && value_obj.value != null && value_obj.value.length > 0) {
    value_obj.value = fixFormat(value, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  }
  return value;
}

function setFocusByTimeOut() {
  var cDate1 = new Date();
  var millisec = cDate1.getMilliseconds();
  if (blurObj != null) {
    if (Math.abs(millisec - timeOutForAlerts) > 100 && blurObj.style.display != 'none') {
      blurObj.focus();
    }
    blurObj = null;
  }
  timeOutForAlerts = millisec;
}

function getIndexByColumnId(columnId) {
  var allColumnsElement = document.getElementById("ALL_COLUMNS");
  if (allColumnsElement == null) return -1;
  var allColumns = allColumnsElement.value;
  var indexOf = allColumns.indexOf("," + columnId + "=");
  var foundLength = ("," + columnId + "=").length;
  if (indexOf < 0) {
    indexOf = allColumns.indexOf(columnId + "=");
    foundLength = (columnId + "=").length;
  }
  if (indexOf < 0) return -1;
  var afterFound = allColumns.substring(indexOf + foundLength);
  var indexOfComa = afterFound.indexOf(",");
  if (indexOfComa < 0) return afterFound;
  else return afterFound.substring(0, indexOfComa);
}

function selectTextInTextBox(obj){
  if(obj==null) return;
  var iCaretPos = obj.value.length;
  if (document.selection){ //IE
    var range = document.selection.createRange();
    if (obj.type == 'text'){
      range.moveStart('character', 0);
      range.moveEnd('character', iCaretPos);
      range.select();
    }
  }
  else if (obj.selectionStart || obj.selectionStart == '0'){ // Firefox
    obj.setSelectionRange(0, iCaretPos);
  }
}

function alertExclusive(qtext) {
  if (qtext.length > 150) {
    qtext = qtext.substr(0, 150) + '...';
  }
  alert(exclusiveAlert.replace(/\{0\}/, qtext));
}

function checkSum(focusObj, fromBody, output_alert, qtext, QID, total_min, total_max, answer_required, preffix, suffix,
                  decimal_place, decimal_divider, thousend_divider) {
  var ok = false,
      i = 1,
      total_sum = new BigNumber(0)/*see bigNumber.js*/,
      count = 0,
      missing_value = null,
      currentForm = (focusObj == null || focusObj == window)
          ? _current_form
          : focusObj.form,
      foundForm = findQuestionElementsOnForm(QID, currentForm);
  if (foundForm.length == 0) return true;
  var checkArray = fillArray(foundForm),
      totalElement = getTotalElement(foundForm, currentForm);
  if (isNaN(checkArray.length)) return true;
  if (total_min == null) total_min = -Number.MAX_VALUE;
  if (total_max == null) total_max = Number.MAX_VALUE;

  var emptyElementsCount = 1;//fillArray put into [0] element some digits, and then elements for check
  while (i < checkArray.length) {
    var elementCheck = checkArray[i];
    if (checkvalue(elementCheck, false, preffix, suffix, decimal_place, decimal_divider, thousend_divider)) count++;
    else missing_value = elementCheck;
    if (elementCheck.value == "") emptyElementsCount++;
    i++;
  }
  i = 1;
  if (totalElement != null && emptyElementsCount == checkArray.length) {// if all fields empty
    totalElement.value = "";
    return true;
  }
  while (i < checkArray.length) {
    if (totalElement != null && focusObj != null && focusObj != window) {
      if (totalElement.form.name == focusObj.form.name) {
        var n = intvalue(focusObj, fromBody, checkArray[i], preffix, suffix, decimal_place, decimal_divider, thousend_divider);
        total_sum = total_sum.add(new BigNumber(n));
      }
    } else if (totalElement != null) {
      var n = intvalue(focusObj, fromBody, checkArray[i], preffix, suffix, decimal_place, decimal_divider, thousend_divider);
      total_sum = total_sum.add(new BigNumber(n));
    }
    i++;
  }
  var tmp_str = new String(total_sum);
  if (totalElement != null) {
    totalElement.value = total_sum;
  }
  if (count == 0) {
    if (!answer_required) {
      ok = true;
      return ok;
    }
  }
  if (total_sum != total_min && total_min == total_max) {
    if (count + 2 >= checkArray.length && missing_value != null) {
      var diff = new BigNumber(total_min).subtract(total_sum);
      if (diff.compare(0) > 0) {
        missing_value.value =
        fixFormat(diff, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
        ok = true;
        tmp_str = total_min;
        if (totalElement != null) totalElement.value =
                                  fixFormat(tmp_str, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
      } else {
        if (!fromBody) missing_value.value =
                       fixFormat(0, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
        ok = false;
        if (totalElement != null) totalElement.value =
                                  fixFormat(tmp_str, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
      }
      return ok;
    } else if (answer_required) {
      i = 1;
      while (i < checkArray.length) {
        if (!checkvalue(checkArray[i], output_alert, preffix, suffix, decimal_place, decimal_divider, thousend_divider)) break;
        i++;
      }
    }
  } else {
    ok = true;
  }
  if (totalElement != null) totalElement.value =
                            fixFormat(tmp_str, preffix, suffix, decimal_place, decimal_divider, thousend_divider);
  if (total_min < total_max && total_sum >= total_min && total_sum <= total_max) {
    ok = true;
    return ok;
  }
  if (missing_value == null && !isNaN(checkArray.length) && checkArray.length > 1) missing_value =
                                                                                   checkArray[checkArray.length - 1];
  var msg = null;
  if (total_min <= total_max && total_sum < total_min) {
    ok = false;
    msg = inTheQue + '"' + qtext + '" \n\n ';
    msg += summLess.replace('{0}', total_min);
  } else if (total_min <= total_max && total_sum > total_max) {
    ok = false;
    msg = inTheQue + '"' + qtext + '" \n\n ';
    msg += summExceeds.replace('{0}', total_max);
  }

  if (!ok && msg != null && output_alert) {
    if (_current_form == null) {
      alert(msg);
      scrollToQuestion = '#Q' + QID;
      window.setTimeout(scrollToSomeQuestion, 250);
      missing_value.focus();
    } else {
      validationErrorAlert = msg;
      validationErrorElement = findElementForHiglite(_current_form, QID);
    }
  }

  return ok;
}

function beforeSubmitErrorAlert(qtext, elem, QID) {
  var msg = '    ' + beforeSubmitMsg + qtext;
  if (_current_form == null) {
    alert(msg);
    elem.focus();
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    validationErrorAlert = msg;
    validationErrorElement = findElementForHiglite(_current_form, QID);
  }
}

function pleaseAnswerAllRowsErrorAlert(hasQText, qtext, elem, QID) {
  if (_current_form == null) {
    var answerFromBundle = pleaseAnswerAllRowsMsg.replace(/(.*):\s*$/, "$1");
    alert('    ' + answerFromBundle + (hasQText ? ':\n' + qtext : ""));
    elem.focus();
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    addElementForHighlite3dMatrixAllRows(_current_form, QID);
  }
}

function reactionOnError(QID, qtext) {
  if (_current_form == null) {
    var answerFromBundle = pleaseAnswerMsg.replace(/(.*):\s*$/, "$1");
    alert('    ' + answerFromBundle + ':\n' + qtext);
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    addElementForHighlite(_current_form, QID);
  }
}

function reactionOnMandatoryAnswerError(QID, aTexts) {
  if (_current_form == null) {
    var answerFromBundle = pleaseRespondToTheFollowingItems.replace(/(.*):\s*$/, "$1");
    var prevStr = '    ';
    var msg = prevStr + answerFromBundle + ':\n';
    var l = aTexts.length;
    for (i = 0; i < l; i++) {
      msg += prevStr + aTexts[i] + ',\n';
    }
    l && (msg=msg.substring(0,msg.length - 2));
    alert(msg);
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    addElementForHighlite(_current_form, QID);
  }
}

function pleaseAnswerErrorAlert(qtext, QID) {
  var answerFromBundle = pleaseAnswerMsg.replace(/(.*):\s*$/, "$1");
  var msg = '    ' + answerFromBundle + ':\n' + qtext;
  if (_current_form == null) {
    alert(msg);
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    validationErrorAlert = msg;
    validationErrorElement = findElementForHiglite(_current_form, QID);
  }
}

function reactionOnErrorMustAnswerAllFields3D(QID, qtext) {
  if (_current_form == null) {
    var answerFromBundle = pleaseAnswerAllMatrixFieldsMsg.replace(/(.*):\s*$/, "$1");
    alert('    ' + answerFromBundle + ':\n' + qtext);
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    addElementForHighlite(_current_form, QID);
  }
}

function showPreferredAlert() {
  var i = 0;
  var j = 0;
  var msg = "" + notAnsweredButPreferredMsg;
  while (i < prefAnsweredQue.length) {
    var QID = prefAnsweredQue[i];
    if (QID > 0 && document.getElementById("QuestionAnswersTableId" + QID) && !validateRequiredGeneralSilent(QID)) {
      msg += " - " + prefAnsweredQueTexts[i] + "\n";
      if (j == 0) scrollToQuestion = '#Q' + QID;
      j++;
    }
    i++;
  }
  msg += isItOkMsg;
  if (j == 0) return true;
  if (confirm(msg) > 0) return true;
  window.setTimeout(scrollToSomeQuestion, 250);
  return false;
}

function alertMinMaxReq(QID, qtext, minRequired, maxAllowed, form) {
  var msg = "";
  if (minRequired <= 1) {
    msg = '   ' + mayCheckFullMsg.replace(/\{0\}/, maxAllowed).replace(/\{1\}/, qtext);
  } else if (maxAllowed == 0) {
    msg = '   ' + chooseAtLeastFullMsg.replace(/\{0\}/, minRequired).replace(/\{1\}/, qtext);
  } else if (minRequired == maxAllowed) {
    msg = '   ' + exactlyFullMsg.replace(/\{0\}/, minRequired).replace(/\{1\}/, qtext);
  } else {
    msg = '   ' + checkFromFullMsg.replace(/\{0\}/, minRequired).replace(/\{1\}/, maxAllowed).replace(/\{2\}/, qtext);
  }
  if (form == null) {
    alert(msg);
    validationErrorAlert = msg;
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    validationErrorAlert = msg;
    validationErrorElement = findElementForHiglite(form, QID);
  }
}

function checkRankGrid(QID, qtext, isRequired, isPreferred, requiredCount, rowCount, uniqueAnswers) {
  if (_current_form != null && validationErrorElement != null) {//in multi forms only one alert should be shown
    return true;
  }
  if (!isQuestionExistInForm(QID, _current_form)) {
    return true;
  }
  if (isPreferred) return true;
  var requiredMsg;
  if (requiredCount == rowCount) {
    requiredMsg = '   ' + pleaseAnswerAllRowsMsg + qtext;
  } else {
    requiredMsg = '   ' + atLeastMsg + ' ';
    if (requiredCount != 1) {
      requiredMsg += requiredCount + " " + rowsMsg;
    } else {
      requiredMsg += oneRowMsg;
    }
    requiredMsg += ' ' + inQueMsg + qtext;
  }
  if (isRequired || isPreferred) {
    if (!validateRequiredGeneralSilent(QID)) {
      if (_current_form == null) {
        alert(requiredMsg);
        scrollToQuestion = '#Q' + QID;
        window.setTimeout(scrollToSomeQuestion, 250);
      } else {
        validationErrorAlert = requiredMsg;
        validationErrorElement = findElementForHiglite(_current_form, QID);
      }
      return false;
    }
  }

  var frm = findQuestionElementsOnForm(QID, _current_form);
  var checkedCount = 0;
  var usedValues = [];
  var usedDuplicate = false;
  var i = -1;
  while ((i + 1) < frm.length && frm[i + 1] != null && frm[i + 1].name != null) {
    i++;
    var elem = frm[i];
    if (elem.name.indexOf("R" + QID + "_") >= 0) {
      if (elem.checked) {
        checkedCount++;
        if (uniqueAnswers && !usedDuplicate) {
          var val = elem.value;
          if (usedValues[val] == 1) usedDuplicate = true;
          else usedValues[val] = 1;
        }
      }
    }
  }
  if (!usedDuplicate) {
    if (checkedCount >= requiredCount) return true;
    if (checkedCount == 0) return true;
  }
  var msg = "";
  if (usedDuplicate) {
    msg = "" + inTheQueMsg + '"' + qtext + '" \n\n ';
    msg += youCanChooseMsg;
  } else {
    msg = requiredMsg;
  }
  if (_current_form == null) {
    alert(msg);
    scrollToQuestion = '#Q' + QID;
    window.setTimeout(scrollToSomeQuestion, 250);
  } else {
    validationErrorAlert = msg;
    validationErrorElement = findElementForHiglite(_current_form, QID);
  }
  return false;
}

function isQuestionInGeneralSection(qid) {
  return j$("#generalSection").find("#questionMainTableId" + qid).length > 0;
}

var stopFormEnter = function(e) {
  e = e || window.event;
  if (e &&
      (e.target && "input" == e.target.tagName.toLowerCase() ||
       e.srcElement && "input" == e.srcElement.tagName.toLowerCase())) {
    return !((e.keyCode || e.which) == 13);
  } else {
    return true;
  }
};

