var baseDir = ( ( typeof( parent.appBaseDir ) != "undefined" ) ? parent.appBaseDir : "" );

//@version	2.0
window.Quest = function( data )
{
  if(data.login)
  {
    Auth.loginPrompt( data.error, function(){ $.getScript( baseDir + "/poll/loadJSON.jsp?pollId=" + data.id +"&r="+ Math.random() ) } );
    return;
  }
  else if( typeof(data.optionLogin)!= "undefined" && data.optionLogin )
  {
    Auth.optionLoginPrompt( data.error, function(){ $.getScript( baseDir + "/poll/loadJSON.jsp?pollId=" + data.id + "&afterLoginOption=t&r="+ Math.random() ) } ); //ask to login but do not enforce it
    return;
  }
  else if( typeof(data.error) != "undefined" )
  {
    $.prompt( data.error, {
             buttons:{ "OK":"t" },
             promptspeed:-1,
             callback:data.callback
            });

    return;
  }

  var qnr = this;
  this.current = 0;
  this.id = data.id;
  this.userId = data.userId;
  this.questions = data.questions;
  this.title = data.title;
  this.intro = data.intro;
  this.custom = data.custom;
  this.avail = data.avail;
  this.saved = data.saved;
  this.answers = data.answers;

  this.unescape = function( strToDecode )
  {
    return unescape((""+strToDecode).replace(/\+/g, " "));
  }


  this.authPrompt = function(ttl,msg,postCall,btns)
  {
    $.prompt( "<h3>"+ttl+"</h3><div id=sv_msg>"+msg+"</div><form>"+
              "<div class=\"formRow\"><label for=sv_un>User Name</label><input type=text tabindex=1 id=sv_un name=username/></div>"+
              "<div class=\"formRow\"><label for=sv_pw>Password</label><input type=password tabindex=2 id=sv_pw name=password/></div>"+
              "</form>",
    {
      "loaded": function()
      {
      	var prmpt = $(this);
        $("#sv_un",$(this)).focus();
        $("#sv_pw",$(this)).keypress(function(e)
        {
          if( (e.keyCode&&e.keyCode == 13) || e.which == 13){ $("button[value=true]",prmpt).trigger("click") }
        });
      },
      "buttons": typeof(btns)!=="undefined"?btns:{"Cancel":false,"Save":true},
      "submit": function( val, msg )
      {
        if( val && ( $("#sv_un",msg).val() == "" || $("#sv_pw",msg).val() == "" ) )
        {
          $.prompt( "Please fill both the username and password if you wish to proceed." );
          return false;
        }
        return !val || ( $("#sv_un",msg).val() != "" && $("#sv_pw",msg).val() != "" );
      },
      "callback": function( val, msg )
      {
        if( val )
        {
          postCall( $("#sv_un",msg).val(), $("#sv_pw",msg).val() );
        }
      }
    });
  }

  this.partSave = function(prompted)
  {
    if(!prompted)
    {
      $.prompt("<h3>Notice</h3><p>Your response to this question will not be saved.</p><p>If you have completed this question and wish to save it, cancel this message, click 'Next' in the survey and then click 'Save' at the next question.</p>", {"buttons":{"Cancel":false,"Continue":true}, "focus":1,"callback":function(btn){ if(btn){ qnr.partSave(true);} } });
      return;
    }

    var subId = (typeof(qnr.saved)!="undefined"?qnr.saved.subId:-1)

    var saveCall = function( saveId, savePass )
    {
      $.ajax({ url:"/poll/partSave.jsp", type:"post", dataType:"json", "data":"pollId="+ qnr.id +"&saveId="+encodeURI(saveId)+"&savePass="+encodeURI(savePass)+"&data="+encodeURI(JSON.stringify(qnr.answers)), success:postSub, error:postSub} );
    }

    // request username and password
    var postSub = function(data,status)
    {
      if( typeof( console ) != "undefined" ) { console.log( data, status ); }
      if(status!="success" || data.error)
      {
        var message = (data.error=="" && data.message=="")?"Save Failed": data.error +"\n"+ data.message;
        qnr.authPrompt("Unable to Save",message,saveCall);
      }
      else
      {
        var msg = "Simply return to the survey page and resume with the username and password you have supplied.";
        if( this.userId>-1 )
        {
          msg = "Simply log-in to your website account and return to the survey page to resume.";
        }

        qnr.saved.saveId = message;

        $.prompt("<h3>Survey Saved</h3><p>Your survey data has been saved.</p><p>You can now close this page or your web browser and return later. " + msg + "</p><p>Note: you may continue now and save again at any time.</p>", {"buttons": {"Close":true} } );
      }
    };


    if( this.userId > -1 && qnr.avail != "a" )
    {
      saveCall( this.userId, "" );
    }
    else
    {
      qnr.authPrompt("Save Your Responses","<p>To save your progress we require a username and password.</p><p>You will need to remember these in order to resume at a later time.</p>", saveCall);
    }

    $.prompt;

  }

  this.proceed = function()
  {
    var btn = $("#dlmSurvey input.cont[type='button']");
    btn.unbind("click");

    if( qnr.current < this.questions.length-1 )
    {
      btn.bind("click",function(i){ if(!qnr.setAnswer()){return;} qnr.reveal(this, 300, qnr.getNextQuestion()) });
    }
    else
    {
      $("#dlmSrvySv").hide();
      btn.val("Submit");
      btn.bind("click",function(i){
        if(!qnr.setAnswer()){return;}
        qnr.send();
      });
    }
  }

  this.send = function()
  {
    var postSub = function(d,s)
    {
      if(d.login)
      {
        Auth.loginPrompt( d.error, function(){$("#dlmSurvey input.cont[type='button']").click()} );
        return;
      }

      if( d.error || s!="success" )
      {
        alert( d.error?d.error:s );
      }

      if( d.callback !== null && typeof( d.callback ) != "undefined" )
      {
        if( d.callback.type === "uri" )
        {
          document.location.href = d.callback.data;
        }
        return;
      }
    }

    if(typeof(console)!= "undefined"){console.log(data, qnr.answers, qnr.answerToQS());}

    $.ajax({ url:data.action, type:"post", dataType:"json", "data":qnr.answerToQS(), success:postSub, error:postSub })
  }

  this.answerToQS = function()
  {
    var ans,rsp;
    var qs = "";
    for( var a = 0; a < qnr.answers.length; a++ )
    {
      ans = qnr.answers[a];
      for( var r = 0; typeof(ans)!="undefined" && ans !== null && r < ans.response.length; r++ )
      {
        rsp = ans.response[r];
        qs += "&q."+ans.id+"=" + ( !rsp.value ? ( "c."+rsp.id + ( rsp.range ? ":r."+escape(rsp.range) : "" ) + ( rsp.other? ":"+escape(rsp.other) : "" ) ) : escape(rsp.value));
      }
    }
    return "pollId="+ qnr.id + (typeof(qnr.saved)==="undefined" || !qnr.saved.saveId?"":"&saveId="+ encodeURI(qnr.saved.saveId)) + qs;
  }

  this.sessionize = function()
  {
    if( !qnr.answers )
    {
      return;
    }

    var postSub = function(d,s)
    {
      if( d.error || s!="success" )
      {
        //alert( d.error?d.error:s );
      }
    }

    $.ajax( {url:"/poll/sessionize.jsp", type:"post", dataType:"json", data:"pollId="+ qnr.id +
    	    (typeof(qnr.saved)==="undefined" || !qnr.saved.saveId?"":"&saveId="+ encodeURI(qnr.saved.saveId)) +
    	    "&pos="+ qnr.current +
    	    "&data="+ escape(JSON.stringify(qnr.answers)),
    	    success:postSub, error:postSub} );
  }

  this.progress = function()
  {
    $("#dlmSurvey .prgrss").text( Math.floor((qnr.current/qnr.questions.length)*100) + "% complete" );
  }

  this.draw = function( qNum )
  {
    qnr.current = qNum;
    var qBox = $("#dlmSurvey .fld");

    qnr.proceed();
    qnr.progress();

    var q = qnr.questions[qNum];

    if(typeof(q.cap)=="undefined")
    {
      q.cap = q.length;
    }

    $("#dlmSrvyCnt").removeClass("intro");
    $("#dlmSrvyCnt").addClass("qstns");
    $("#dlmSurvey h3 .qNum").text( q.numberLabel==="" ? "Q"+qNum+"." : q.numberLabel );
    $("#dlmSurvey h3 .qTxt").text( " "+qnr.unescape(q.question));

    $("#dlmSurvey .desc").html( ( q.desc )?( qnr.unescape(q.desc) ):("") );

    var optNote = $("#dlmSurvey .note");
    var footNote = $("#dlmSurvey .ftNote");
    var headNote = $("#hdNote");

    optNote.html("");
    footNote.html("");
    headNote.html("");
    qBox.html("");


    if(q.type=="select-one" || q.type=="radio")
    {
      optNote.html("Select just one option");
    }
    else if(q.type.indexOf("select")==0 || q.type=="checkbox")
    {
      optNote.html("Select as many options as required");
    }
    else if(q.type=="range")
    {
      optNote.html("For each row below, click the button that corresponds to the answers at the top");
    }
    else if(q.type=="order")
    {
      optNote.html("Please rank every item, highest number is favourite");
    }
    else if( q.type=="multi-number" && q.options.length > 1)
    {
      optNote.html( "Type a number into each field below" + (q.cap>-1?". The total for all fields should be "+q.cap:"") );
    }
    else if( q.type=="multi-text" && q.options.length > 1)
    {
      optNote.html( "Type into the fields below" );
    }
    else if( q.type=="numeric" || q.type=="multi-number" && q.options.length==1 )
    {
      optNote.html("Enter a number " + (q.cap>0?"between 0 and "+q.cap:""));
    }
    else if( q.type=="date")
    {
      optNote.html("Supply a date");
    }
    else if( q.type=="time")
    {
      optNote.html("Supply a time");
    }
    else if( q.type=="datetime")
    {
      optNote.html("Supply date and time");
    }
    else if( !q.type=="text")
    {
      optNote.html("Enter your choice");
    }
    else
    {
      optNote.html("Type your answer into the field below");
    }
    // custom rendering
    try
    {
      if( qnr.custom.render.call( qnr, q ) )
      {
        return;
      }
    }
    catch(ex){ if(typeof(console)!="undefined"){console.log( ex );} }


    if(q.type.indexOf("select")==0)
    {
      qBox.append("<select id=opts>");
      var fld = $("#opts");
      if( q.type!="select-one" )
      {
        fld.attr("multiple","multiple");
      }
      else
      {
        fld.append("<option>");
      }
      $.each(q.options, function(i,val){fld.append("<option "+ (typeof(this.other) != "undefined"?"other=\"t\"":"") +" value=\""+this.id+"\">"+qnr.unescape(this.label)+"</option>")} );
      $("#opts option").attr("selected","");
      $("#opts").change(function(){ ($("#opts option[other='t']:selected").length==0?qnr.hideOther(q):qnr.showOther(q)) });
    }
    else if( q.type=="range" || q.type=="order" ||  q.type=="checkbox" || q.type=="radio" )
    {
      qBox.append("<div id=opts>");
      $("#opts").append("<div id=optsCnt>");

      if( q.type=="range" || q.type=="order" )
      {
        var optTable = $("<table>").appendTo("#optsCnt");
        var optRow = $("<tr>").append("<th style=\"width:33%\"/>").appendTo(optTable);

        // range labels
        var rng = (q.type=="order"?q.options:q.range);
        $.each( rng, function(i,val)
        {
          optRow.append( $("<th style=\"width:"+(66/(rng.length)) +"%\">").text( (q.type=="order"?(i+1):qnr.unescape(val.label)) ) );
        } );

        //ratings
        $.each(q.options, function(j,opt)
        {
          optRow = $("<tr/>").append( $("<th class=\"rangeLabel\"/>").text(qnr.unescape(opt.label)) ).appendTo(optTable);
          $.each( rng, function(i,val)
          {
            optRow.append( $("<td/>").append("<input type=\"radio\" id=\"itm_"+j+"_"+i+"\" name=\"itm_"+j+"\" "+ ((typeof(opt.other) != "undefined")?" other=\"t\"":"") +" value=\""+ (q.type=="order"?i+1:val.id) +"\"/>") );
          } );
        } );
      }
      else
      {
        $.each(q.options, function(i,val){
          $("#optsCnt").append("<div><input type=\""+(q.type=="select-one"||q.type=="radio"?("radio"):("checkbox"))+"\" id=\"itm_"+i+"\" name=\"itm\" "+ (typeof(this.other) != "undefined" ? " other=\"t\"":"") +" value=\""+this.id+"\"/><label for=\"itm_"+i+"\">"+qnr.unescape(this.label)+"</label></div>")
        } );

        $("#optsCnt input").removeAttr("checked");
      }

      $("#optsCnt :radio, #optsCnt :checkbox").click( function()
      {
        if( this.type == "radio" )
        {
          if( $(this).attr("set") == "t" )
          {
            this.checked=false;
          }
          else
          {
            $(this).attr("set","t");
          }
          $("#optsCnt :radio:not(:checked)").removeAttr("set");
        }

        if($("#optsCnt input[other='t']:checked").length==0)
        {
          qnr.hideOther(q)
        }
        else if( $("#itm_oth").length < 1 )
        {
          qnr.showOther(q);
        }

        if( q.cap > 0 )
        {
          if( $("#optsCnt :checked").length >= q.cap )
          {
            $("#optsCnt :checkbox:not(:checked)").attr("disabled","disabled");
          }
          else
          {
            $("#optsCnt :checkbox:disabled").removeAttr("disabled");
          }
        }

        if( q.type=="order" ) //mutex locking
        {
          $.each($("#optsCnt :radio:not(:checked)"), function(i,val)
          {
            if( $("#optsCnt :radio[value='"+this.value+"']:checked").length > 0 )
            {
              $(this).fadeTo(0,0.1).attr("disabled","disabled");
            }
            else
            {
              $(this).fadeTo(0,1).removeAttr("disabled");
            }
          });
        }

        $.each($("#optsCnt div"), function(i,val)
        {
          if( $(":checked",this).length>0 )
          {
            $(this).addClass("chk")
          }
          else
          {
            $(this).removeClass("chk");
          }
        })
      });
    }
    else if( q.type=="multi-text" || q.type=="multi-number"  )
    {
      var optRow, optTable = $("<table>").appendTo(qBox);
      $.each(q.options, function(i,val){
        optRow = $("<tr/>").append( $("<th/>").append( $("<label for=\"itm_"+i+"\"/>").text(qnr.unescape(this.label)) ) ).appendTo(optTable);
        if( q.type=="multi-text" && this.label.toLowerCase() == "address" )
        {
          optRow.append("<td><textarea class=formElement id=\"itm_"+i+"\" name=\"itm_"+i+"\" rows=\"3\" cols=\"50\"></textarea></td>");
        }
        else
        {
          optRow.append("<td><input type=text class=formElement id=\"itm_"+i+"\" name=\"itm_"+i+"\" value=\"\"/></td>");
        }
      });
    }
    else if( q.type=="text" || q.type=="numeric" )
    {
      var len = (isNaN(parseInt(q.cap)) ? 50 : q.cap);
      if( q.type=="numeric"  )
      {
        qBox.append("<input id=\"optsCnt\" class=\"formElement\" name=\"itm\" value=\"\" />");
      }
      else if( len > 0 && len <= 50 )
      {
        qBox.append("<input id=\"optsCnt\" class=\"formElement\" name=\"itm\" value=\"\" maxlength=\"100\"/>");
      }
      else
      {
        qBox.append("<textarea id=\"optsCnt\" class=\"formElement\" name=\"itm\" rows=\"4\"></textarea>");
      }
    }

    // custom rendering
    try
    {
      qnr.custom.render.call( qnr, q, true );
    }
    catch(ex){ if(typeof(console)!="undefined"){console.log( ex );} }

  }

  this.setAnswer = function()
  {
    var q = qnr.questions[ Math.min(qnr.current, qnr.questions.length-1) ];
    var err = []
    var re = null, opt;
    if( typeof(qnr.answers) == "undefined")
    {
      qnr.answers = [];
    }

    answer = {id:q.id, response:[]};


    // custom answer checking and object storage
    var skipDefaultChecks = false;
    try
    {
      skipDefaultChecks = qnr.custom.store.call( qnr, q, answer );
    }
    catch(ex){if(typeof(console)!="undefined"){console.log(ex);}}


    if( !skipDefaultChecks )
    {
      if(q.type.indexOf("select")==0 || q.type=="checkbox" || q.type=="radio")
      {
        var opt = $("#optsCnt input:checked[value!='']");
        if(q.type.indexOf("select")==0)
        {
          opt = $("#opts option:selected[value!='']");
        }

        if( opt.length==0 )
        {
          err.push("Please make a selection before proceeding");
        }
        else
        {
          opt.each(function(i,val){
            if( $(this).attr("other")=="t" )
            {
              if( $("#itm_oth :input").val()=="" )
              {
                err.push("Please enter your 'other' entry before proceeding");
              }
              answer.response.push( {"id":$(this).val(), "other":$("#itm_oth :input").val()} );
            }
            else
            {
              answer.response.push( {"id":$(this).val()} );
            }
          });
        }
      }
      else if(q.type=="range"||q.type=="order")
      {
        $.each(q.options, function(i,val)
        {
        	opt = $("[name=itm_"+i+"]:checked");
          if( opt.length == 0 && val.other == "t" )
          {
            return true; //continue;
          }

          if( opt.length == 0 )
          {
            err.push("Please make a selection for \""+ qnr.unescape(this.label)+"\" before proceeding");
          }
          else if( val.other=="t" && $("#itm_oth :input").val()=="" )
          {
            err.push("Please enter your 'other' entry before proceeding");
          }
          else
          {
            if( val.other=="t" )
            {
              answer.response.push( {"id":this.id, "range":opt.val(), "other":$("#itm_oth :input").val()} );
            }
            else if( q.type=="order" )
            {
              answer.response.push( {"id":this.id, "other":opt.val()} );
            }
            else
            {
              answer.response.push( {"id":this.id, "range":opt.val()} );
            }
          }
        });
      }
      else if( q.type=="multi-text" || q.type=="multi-number"  )
      {
        var optVal, sum=0;
        $.each(q.options, function(i,val)
        {
          optVal = $("#itm_"+i).val();
          if( q.type=="multi-number" )
          {
            if( !qnr.isInteger( optVal ) )
            {
              err.push("Please enter a whole number for \""+ qnr.unescape(this.label)+"\" before proceeding");
              return true;
            }
            sum += parseInt(optVal,10);
          }

          if( optVal.length < 1 )
          {
            err.push("Please enter a response for \""+ qnr.unescape(this.label)+"\" before proceeding");
          }
          else
          {
            answer.response.push( {"id":this.id,"other":optVal} );
          }
        });

        if( q.type=="multi-number" && q.cap > 0 && sum != q.cap && err.length == 0 )
        {
          err.push("All values must total "+q.cap+". Current total is "+sum );
        	answer.response = [];
        }
      }
      else //text
      {
        var optVal = $(".fld :input").val();
        if( optVal == "" )
        {
          err[err.length]="Please provide a response before proceeding";
        }
        else if( q.type=="numeric" && !qnr.isInteger( optVal ) )
        {
          err[err.length]="Please provide a whole number before proceeding";
        }
        else if( q.type=="numeric" && q.cap > -1 && (parseInt(optVal,10) < 0 || parseInt(optVal,10) > q.cap) )
        {
          err[err.length]="Please provide a number between 0 and "+q.cap+" (inclusive)";
        }
        else
        {
          answer.response[0] = {"value":optVal};
        }
      }
    }

    if(err.length>0)
    {
      alert(" * " + err.join("\n * "));
      qnr.proceed();
      return false;
    }

    qnr.answers[this.current] = answer;
    qnr.sessionize();

    if(typeof(console)!= "undefined"){console.log(answer);}
    $("#dlmSrvySv").show();
    return true;
  }

  this.showOther = function( q )
  {
    if( $("#optsCnt table").length > 0 )
    {
      $("#optsCnt table").append("<tr id=\"itm_oth\"><td></td><td colspan=\""+ $("#optsCnt table tr:eq(1) td").length +"\"><div style=\"display:none\"><input name=\"itm_oth\"/></div></td></tr>");
    }
    else
    {
      $("#optsCnt").append("<div id=\"itm_oth\" style=\"display:none\"><input name=\"itm_oth\"/></div>");
    }
    $("div#itm_oth, #itm_oth div").show(100).find("input").focus();
  }

  this.hideOther = function( q )
  {
    $("div#itm_oth, #itm_oth div").hide(100,function(){$("#itm_oth").remove();});
  }

  this.init = function( element )
  {
    var container = $("#dlmSrvyCnt");
    if( container.length == 0 )
    {
      $("body").append("<div id=\"dlmSrvyCnt\"></div>");
      container = $("#dlmSrvyCnt");
    }

    var formHtml="<div class=\"minH\"></div><div class=\"wrp1\"><form id=\"dlmSurvey\" action=\""+(typeof(qnr.action)=="undefined"?"#":qnr.action)+"\" onsubmit=\"return false\" method=\"post\"><h1></h1><div id=hdNote></div><div class=\"wrp2\"><fieldset><legend></legend><h3><span class=qNum></span><span class=qTxt></span></h3><div class=\"qtn\"><div class=\"desc\"></div><span class=\"note\"></span><div class=\"fld\"></div><span class=\"ftNote\"></span><div class=\"formButtons\"><input type=\"button\" class=\"cont\" value=\"Start\"/> <input type=\"button\" class=\"rsm\" value=\"Resume\"/></div></div></div></fieldset><div class=\"formButtons\"><input type=\"button\" id=\"dlmSrvySv\" value=\"Save\" style=\"display:none\"/ ><input type=\"button\" class=\"cont\" value=\"Next\"/></div><div class=\"prgrss\"><div></div></div></div></form></div>";

    container.html(formHtml);
    $("#dlmSurvey h1").html(qnr.title);

    var btn = $("#dlmSurvey input.cont[type='button']");

    var resumeLogin = function(msg)
    {
      msg = (typeof(msg)!=="undefined"?msg:"In the form below, type the username and password used when you saved your progress.");
      qnr.authPrompt(
      "Resume Saved Survey",msg,
      function(u,p)
      {
        $.getScript( baseDir + "/poll/loadJSON.jsp?pollId="+ qnr.id +"&resume=t&saveId="+ encodeURI(u) +"&savePass="+ encodeURI(p) +"&r="+ Math.random() );
      },
      {"Cancel":false,"Continue":true});
    }

    if( typeof(qnr.saved) !== "undefined" && !qnr.saved.success )
    {
      if( qnr.avail != "a" && qnr.userId>-1 )
      {
        $.prompt("<h3>Notice</h3>Details you have entered into this question will not be saved.", {"buttons":{"Cancel":false,"Continue":true}, "focus":1,"callback":function(btn){ if(btn){ qnr.partSave(true);} } });
      }
      else
      {
        resumeLogin("Unable to resume survey progress. Please ensure that your username and password match those supplied when your progress was saved.");
      }
    }

    if( typeof(qnr.saved) !== "undefined" && typeof(qnr.saved.answers) !== "undefined" && qnr.saved.answers.length > 0 )
    {
      qnr.answers = qnr.saved.answers;
      qnr.current = qnr.getQuestionPosition( qnr.answers[qnr.answers.length-1].id );
      qnr.reveal( btn, 300, Math.min(qnr.getNextQuestion(), qnr.questions.length-1) );
      $("#dlmSrvySv").show();
      qnr.sessionize();
    }
    else
    {
      container.addClass("intro");
      $("#dlmSurvey .desc").html(qnr.intro);
    }

    btn.bind("click", function(){ qnr.reveal(this, 300, qnr.current, "Next") });
    $("#dlmSrvySv").click(function(){ qnr.partSave() });


    $("#dlmSurvey .formButtons .rsm").bind("click", function(){
      if( qnr.avail != "a" && qnr.userId>-1 )
      {
        $.getScript( baseDir + "/poll/loadJSON.jsp?resume=t&pollId=" + qnr.id +"&r="+ Math.random() );
      }
      else
      {
         resumeLogin();
      }
    });

  }

  this.reveal = function(btn, speed, qstnNr, btnTxt )
  {
    $("#dlmSurvey fieldset").css("visibility","hidden");
    if(typeof(btnTxt) == "string" ){$(btn).val(btnTxt);}
    qnr.draw(qstnNr);
    $("#optsCnt").css({left:Math.round(($("#dlmSurvey .fld").width()/2) - ($("#optsCnt").width()/2))+"px"});
    $("#dlmSurvey fieldset").css("visibility","visible");
  }

  this.isInteger = function( toCheck )
  {
    toCheck = toCheck.replace(/[^0-9\.]+/,"");
    return !( isNaN(parseInt(toCheck, 10)) || toCheck != parseInt(toCheck, 10) );
  }


  /*
   * help functions for routing and other custom logic
   */

  this.getQuestion = function( ident, returnPosition )
  {
    returnPosition = (typeof(returnPosition)!=="boolean" ? false : returnPosition);
    ident          = (typeof(ident.type)!=="undefined" ? ident.id : ident); //  been passwed a question obj

    var q;
    var qs = this.questions;
    var byId = typeof(ident)==="number";

    ident = (byId ? ident : ident.toUpperCase())+"";

    for( var i = 0, len = qs.length; i < len; i++ )
    {
      try
      {
        q = qs[i];
        if( (byId && q.id+"" === ident ) || (!byId && q.numberLabel.toUpperCase() === ident) )
        {
          return returnPosition ? i : qs[i];
        }
      }
      catch(e){}
    }
    return returnPosition ? -1 : null;
  }

  this.getQuestionPosition = function( numberLabel )
  {
    return qnr.getQuestion( numberLabel, true );
  }

  window.tmp = qnr;
  window.tmpd = data;

  this.getRangeByLabel = function( question, label )
  {
    label = label.toUpperCase();

    if( typeof(question.type)==="undefined" )
    {
      question = qnr.getQuestion(question);
    }

    try
    {
      var rs = question.range;
      for( var i = 0, len = rs.length; i < len; i++ )
      {
        if( qnr.unescape(rs[i].label).toUpperCase() === label+"" )
        {
          return rs[i];
        }
      }
    }
    catch(e){}
    return null;
  }

  this.getRangeByValue = function( question, val )
  {
    val = val.toUpperCase();

    if( typeof(question.type)==="undefined" )
    {
      question = qnr.getQuestion(question);
    }

    try
    {
      var rs = question.range;
      for( var i = 0, len = rs.length; i < len; i++ )
      {
        if( qnr.unescape(rs[i].value).toUpperCase() == val )
        {
          return rs[i];
        }
      }
    }
    catch(e){}
    return null;
  }

  this.getChoiceByLabel = function( question, label )
  {
    label = label.toUpperCase();
    try
    {
      var cs = question.options;
      for( var i = 0, len = cs.length; i < len; i++ )
      {
        if( qnr.unescape(cs[i].label).toUpperCase() === label+"" )
        {
          return cs[i];
        }
      }
    }
    catch(e){}
    return null;
  }

  this.getChoiceByValue = function( question, val )
  {
    val = val.toUpperCase();
    try
    {
      var cs = question.options;
      for( var i = 0, len = cs.length; i < len; i++ )
      {
        if( qnr.unescape(cs[i].value).toUpperCase() === val+"" )
        {
          return cs[i];
        }
      }
    }
    catch(e){}
    return null;
  }

  this.getAnswerByQuestionId = function( id )
  {
    try
    {
      var as = qnr.answers;
      for( var i = 0, len = as.length; i < len; i++ )
      {
        if( typeof(as[i])!=="undefined" && as[i] !== null && as[i].id+"" === id+"" )
        {
          return as[i];
        }
      }
    }
    catch(e){}
    return null;
  }

  this.getAnswerByQuestion = function( handle )
  {
    var q = qnr.getQuestion(handle);
    return qnr.getAnswerByQuestionId( q.id );
  }


  /* returns choice object from answers array */
  this.answerHasChoice = function( subject, choice )
  {
    var a, q;
    if( typeof(subject)==="object" && typeof(subject.response)!=="undefined" )		// subject is an answer
    {
      a = subject;
      q = qnr.getQuestion(a.id);
    }
    else										// subject is a question handle or id
    {
      if( typeof(subject)==="object" && typeof(subject.question)!=="undefined" )	// subject is a question object
      {
        q = subject;
      }
      else						// subject is a question Id
      {
        q = qnr.getQuestion(subject);
      }

      a = qnr.getAnswerByQuestionId( q.id );
    }

    try
    {
      choice = (typeof(choice)==="number" ? choice : qnr.getChoiceByLabel(q, choice).id );	// check if choice is a label
    }
    catch( e )
    {
      try
      {
        choice = qnr.getChoiceByValue(q, choice).id;	// check if choice is a value
      }
      catch( e )
      {
        choice = -1;
      }
    }

    try
    {
      var ch = a.response;
      for( var i = 0, len = ch.length; i < len; i++ )
      {
        if( (ch[i].id+"") === choice+"" )
        {
          return ch[i];
        }
      }
    }
    catch(e){}
    return null;
  }

  this.answerChoiceIsRange = function( subject, choice, range )
  {
    var r;
    if( typeof(range.label)!=="undefined") // is a range object
    {
      r = range.id;
    }
    else
    {
      try
      {
        r = (typeof(range)==="number" ? range : qnr.getRangeByLabel(q, range).id );	// check if range is a label
      }
      catch( e )
      {
        try
        {
          r = qnr.getRangeByValue(q, range).id;	// check if range is a value
        }
        catch( e )
        {
          r = -1;
        }
      }
    }

    var c = qnr.answerHasChoice( subject, choice );


    return ( c.range+"" === r+"" );
  }


  /*override this function to implement response-based skipping */
  this.getNextQuestion = function()
  {
    try
    {
      var nextQ = qnr.custom.routing.call( qnr, qnr.questions[qnr.current] );
    }
    catch(e){ if(typeof(console)!="undefined"){console.log( "getNextQuestion exception", e );} }

    return (typeof(nextQ)=="number" ? nextQ : qnr.current+1);
  }

  $(function(){qnr.init()});
}
