/************************************************************************* 
 Utils functions
**************************************************************************/
var maMPlata = [];
maMPlata[0] = 'Necompletat';
maMPlata[1] = 'Transfer bancar';
maMPlata[2] = 'Transfer rapid de bani';
maMPlata[3] = 'Mandat postal';

function AjaxRun(pURL, pData, pFunction)
{
	var ret = 1;					
	$("#ajaxResult").val('');
	
	$.ajax({
		type: "POST",
		url: pURL,
		data: pData,
		error: function(request, error){
			ret = 0;
		},
		success: pFunction
	});  
	
	return ret;
}

function Disable(pCtrl){
	$("#" + pCtrl).attr('disabled', 'true');
}

function Enable(pCtrl){
	$("#" + pCtrl).removeAttr('disabled');;
}

function CtrlEmpty(pCtrl){
	return $("#" + pCtrl).val().length == 0;
}

function FocusOn(pCtrl){
	$("#" + pCtrl).focus();
}

function ShowPanel(pPanel){
	$("#" + pPanel).show();
}

function ShowAndWrite(pPanel, pText){
	$("#" + pPanel).html(pText);
	$("#" + pPanel).show();
}

function ChangeAttr(pPanel, pAttr, pValue){
	$("#" + pPanel).attr(pAttr, pValue);
}

function ClearPanel(pPanel){
	$("#" + pPanel).html("");
}

function ClearAndHidePanel(pPanel){
	$("#" + pPanel).html("");
	$("#" + pPanel).hide();
}

function HidePanel(pPanel){
	$("#" + pPanel).hide();
}

function LoadingPanel(pPanel){
	$("#" + pPanel).html("<img src='/images/loading32x32.gif' border='0' >");
}

function LoadingPanelCuText(pPanel, text){
	$("#" + pPanel).html("<img src='/images/loading32x32.gif' border='0' > " + text);
}

/*
function ErrorPanel(pPanel, pText){
	var msg = pText;
	$("#" + pPanel).html(msg);
	$("#" + pPanel).show();
	
}
*/

function ErrorPanel(pPanel, pText, pWithLoading, pInchid){
	var msg = pText;
	if (pInchid){
		//msg = msg + " | <span class=\"Links\" onclick='javascript:$(\"#" + pPanel + "\").hide(\"slide\", { direction: \"up\" }, 1000);'>închid</span>";
		msg = msg + " | <span class=\"Links\" onclick='javascript:$(\"#" + pPanel + "\").hide();'>închid</span>";
	}
	$("#" + pPanel).html(msg);
	//$("#" + pPanel).show("slide", { direction: "up" }, 1000);
	$("#" + pPanel).show();
}

function ErrorPanelCuButon(pPanel, pText, pWithLoading, pInchid){
	var msg = pText;
	if (pInchid){
		msg = "<div>" + msg + "</div><div style='text-align: right; padding: 2px;'><button style='padding: 4px;' onclick='javascript:$(\"#" + pPanel + "\").hide();'>închid</button></div>";
	}
	$("#" + pPanel).html(msg);
	//$("#" + pPanel).show("slide", { direction: "up" }, 1000);
	$("#" + pPanel).show();
}

function MsgPannel(pPanel, pText, pWithLoading, pInchid){
	var msg = pText;
	if (pWithLoading){
		msg = msg + " <img src='/images/loader-line.gif' border='0' style='margin-rught: 2px;' >";
	}
	
	if (pInchid){
		msg = msg + " | <span class=\"Links\" onclick='javascript:$(\"#" + pPanel + "\").hide();'>închid</span>";
	}
	$("#" + pPanel).html(msg);
	//$("#" + pPanel).show("slide", { direction: "up" }, 1000);
	$("#" + pPanel).show();
}

function MsgPannelCuButon(pPanel, pText, pWithLoading, pInchid){
	var msg = pText;
	if (pWithLoading){
		msg = msg + " <img src='/images/loader-line.gif' border='0' style='margin-rught: 2px;' >";
	}
	
	if (pInchid){
		msg = "<div>" + msg + "</div><div style='text-align: right; padding: 2px;'><button style='padding: 4px;' onclick='javascript:$(\"#" + pPanel + "\").hide();'>închid</button></div>";
	}
	$("#" + pPanel).html(msg);
	//$("#" + pPanel).show("slide", { direction: "up" }, 1000);
	$("#" + pPanel).show();
}

function trim (str) {
	var	str = str.replace(/^\s\s*/, ''),
		ws = /\s/,
		i = str.length;
	while (ws.test(str.charAt(--i)));
	return str.slice(0, i + 1);
}

function ValidateEmail(email) {
	var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;   
	if(reg.test(email) == false) {      
		return false;
	} else {
		return true;
	}
}

function RoundNumber(num, dec) {
	var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
	return result;
}

function ScrollToElement(theElement){

	var selectedPosX = 0;
	var selectedPosY = 0;
	          
	while(theElement != null){
	selectedPosX += theElement.offsetLeft;
	selectedPosY += theElement.offsetTop;
	theElement = theElement.offsetParent;
	}
                        		      
	window.scrollTo(selectedPosX,selectedPosY);
}

function numbersonly(myfield, e, dec) {
    var key;
    var keychar;

    if (window.event)
        key = window.event.keyCode;
    else if (e)
        key = e.which;
    else
        return true;
    keychar = String.fromCharCode(key);

    // control keys
    if ((key == null) || (key == 0) || (key == 8) ||
    (key == 9) || (key == 13) || (key == 27))
        return true;

    // numbers
    else if ((("0123456789").indexOf(keychar) > -1))
        return true;
	else if (myfield.value.split(',').length > 1)
		return false;
	else if (((",").indexOf(keychar) > -1))
        return true;
    // decimal point jump
    //else if (dec && (keychar == ".")) {
        //myfield.form.elements[dec].focus();
        //return false;
    //   return true;
    //}
    else
        return false;
}

function isNumeric(sText) {
   var ValidChars = "0123456789.";
   var IsNumber=true;
   var Char;

   if(typeof sText === "undefined") { return false; } 
   
   for (i = 0; i < sText.length && IsNumber == true; i++) 
      { 
      Char = sText.charAt(i); 
      if (ValidChars.indexOf(Char) == -1) 
         {
         IsNumber = false;
         }
      }
   return IsNumber;
   
}

function formatNumbers(pSelector){
	$(pSelector + ':not(.formatted_nr)').each(function(index) {
		if (jQuery.trim($(this).text()).length > 0){
			var mval = $(this).text();
        	$(this).text(mval.replace('.',','));
			$(this).format();
			$(this).addClass("formatted_nr");
		}         
    });
    //$(pSelector).format();
	return true;
}

function formatNumber(pSelector){	
	if (jQuery.trim($(pSelector).text()).length > 0) {
		var mval = $(pSelector).text();
		$(pSelector).text(mval.replace('.', ','));
		$(pSelector).format();
	}
}

/************************************************************************* 
 END of Utils functions
**************************************************************************/

/************************************************************************* 
 Classes
**************************************************************************/

function Vanzare() {
    /*properties*/
    this.IDF = 0;
	this.DocTip = 1;
    this.DocData = "";
    this.DocNr = "";
    this.Valoare = 0;
    this.Articole = [];
    this.Furnizori = new Array();
	this.Discounturi = new Array();
	this.Eroare = "";
    /*END of properties*/

    /*methods*/
	this.Clear = function() {		
		this.DocData = "";
	    this.DocNr = "";
	    this.Valoare = 0;
	    this.Articole = [];
		this.AdaugArticol();		
		this.PutDataToForm();
	}
	
	this.Salvez = function() {
		var r = false;
		var mp = new Array();
		var mpa = new Array();
		var md = new Array()
		
		md = { s: "vanzreg", 
			df: this.IDF,
			dt: this.DocTip,
			dd: this.DocData,
			dn: this.DocNr,
			dv: this.Valoare,
			cs: $("#txtCodSec").val(),
			na: this.Articole.length };
		$.each(this.Articole, function(i,v) {
			md["a" + (i + 1) + "d"] = v.Denumire;
			md["a" + (i + 1) + "t"] = v.Cantitate;
			md["a" + (i + 1) + "v"] = v.Valoare;
			md["a" + (i + 1) + "a"] = v.TVA;
			md["a" + (i + 1) + "c"] = v.ComisionID;
		});
		
		ClearAndHidePanel("pnlErr");
		ClearAndHidePanel("pnlMsg");
		
		MsgPannel("pnlMsg", "Înregistrez vanzarea.", true, false);						
		var mt = this;
		$.post("../../lib/scripts/ws.php", md,
			function(data){
				ClearAndHidePanel("pnlErr");
				ClearAndHidePanel("pnlMsg");
				
				if (trim(data) == "OK") {
					MsgPannel("pnlMsg", "Achiziția a fost înregistrată.", false, true);
					mt.Clear();
					mt.DrawArticole('#dContinutArticole');
				} else {					
					ErrorPanel("pnlErr", data, false, true);
				}
				$("#captcha").attr("src", "../../lib/securimage/securimage_show.php?timestamp=" + new Date().getTime());
				$("#txtCodSec").val('');
		});			
		
		return r;
	}
	
	this.Validez = function() {
		var r = true;
		this.Eroare = "";
		
		if (this.IDF <= 0){
			this.Eroare += "Furnizorul nu este completat!<br/>";
			r = false;
		}
		
		if (this.DocTip <= 0){
			this.Eroare += "Tipul documentului nu este completat!<br/>";
			r = false;
		}
		
		if (this.DocData.length == 0){
			this.Eroare += "Data documentului nu este completata!<br/>";
			r = false;
		}
		
		if (this.DocNr <= 0){
			this.Eroare += "Numarul documentului nu este completat!<br/>";
			r = false;
		}
		
		if (this.Valoare.length <= 0){
			this.Eroare += "Valoarea documentului nu este completata!<br/>";
			r = false;
		} else {
			if (isNaN(this.Valoare)){
				this.Eroare += "Valoarea documentului nu este completata corect!<br/>";
				r = false;
			} else {
				if (parseFloat(this.Valoare) <= 0){
					this.Eroare += "Valoarea documentului trebuie sa fie mai mare de 0!<br/>";
					r = false;
				}				
			}
		}
		
		if (r == true) {
			var ra = true;
			var mt = this;
			$.each(this.Articole, function(i, v) {
				if (v.Denumire.length == 0) {
					mt.Eroare += "Denumirea articolului #" + v.Nrc + " nu este completata!<br/>";
					ra = false;
				}
				else {
					if (v.Valoare.length <= 0) {
						mt.Eroare += "Pretul unitar al articolului #" + v.Nrc + " nu este completat!<br/>";
						ra = false;
					}
					else {
						if (isNaN(v.Valoare)) {
							mt.Eroare += "Preturl unitar al articolului #" + v.Nrc + " nu este completat corect!<br/>";
							ra = false;
						}
						else {
							if (parseFloat(v.Valoare) <= 0) {
								mt.Eroare += "Pretul unitar al articolului #" + v.Nrc + " trebuie sa fie mai mare de 0!<br/>";
								ra = false;
							} else {
								if (this.DocTip == 1 && v.TVA.length == 0) {
									mt.Eroare += "Valoarea TVA a  articolului #" + v.Nrc + " nu este completata!<br/>";
									ra = false;
								} else {
									if (this.DocTip == 1 && isNaN(v.TVA)) {
										mt.Eroare += "Valoare TVA a articolului #" + v.Nrc + " nu este completata corect!<br/>";
										ra = false;
									}
									else {
										if (this.DocTip == 1 && parseFloat(v.TVA) <= 0) {
											mt.Eroare += "Valoarea TVA a articolului #" + v.Nrc + " trebuie sa fie mai mare de 0!<br/>";
											ra = false;
										}
									}
								}
							}
						}
					}
				}
				return ra;
			});
			r = ra;
		}
		
		if (r == true){
			var mtotal = 0;
			var mt = this;
			$.each(this.Articole, function(i, v) {
				if (mt.DocTip == 1) {
					mtotal += parseFloat(v.Valoare) + parseFloat(v.TVA); //mtotal += parseFloat(v.Cantitate) * parseFloat(v.Valoare) + parseFloat(v.TVA);
				} else {
					mtotal += parseFloat(v.Valoare); //mtotal += parseFloat(v.Cantitate) * parseFloat(v.Valoare);
				}
			});
			if (mtotal != parseFloat(this.Valoare)){
				mt.Eroare += "Totalul vanzarii nu corespunde cu suma valorilor articolelor!<br/>";
				r = false;
			}
		}
		
		if (r == true){
			if ($("#txtCodSec").val().length == 0){
				this.Eroare += "Codul de securitate nu este completat!<br/>";
				r = false;
			}
		}
		
		return r;
	}
	
    this.AdaugArticol = function () {
        var ma = new Articol();
        ma.Nrc = this.Articole.length + 1;
        this.Articole[this.Articole.length] = ma;
    };
	
    this.StergArticol = function (nrc) {		
		if (this.Articole.length <= 1) return false;
		this.GetDataFromForm();
        if (this.Articole.length > nrc - 1) {
            this.Articole.splice(nrc - 1, 1);
        }
		var mnr = 1;
		$.each(this.Articole, function(i, v) {
			v.Nrc = mnr;
			mnr++;
		});
		this.PutDataToForm();
		return true;
    };
	
	this.GetDataFromForm = function() {
		this.IDF = $("#cmbFurnizor").val();
		this.DocTip = $("#cmbTipDocument").val();
		this.DocData = $("#txtDataDocument").val();
		this.DocNr = $("#txtNumarDocument").val();
		this.Valoare = $("#txtValoareDocument").val();
		$.each(this.Articole, function(i, v) {
			v.GetDataFromForm();
		});
	};
	
	this.PutDataToForm = function() {
		$("#cmbFurnizor").val(this.IDF);
		$("#cmbTipDocument").val(this.DocTip);
		$("#txtDataDocument").val(this.DocData);
		$("#txtNumarDocument").val(this.DocNr);
		$("#txtValoareDocument").val(this.Valoare);
		$.each(this.Articole, function(i, v) {
			v.PutDataToForm();
		});
	};

    this.DrawArticole = function (divArticole) {
        var ms = "";
        $.each(this.Articole, function (i, v) {
            ms += v.Draw();
        });
        $(divArticole).html(ms);
		if($("#cmbTipDocument").val() == 1) {
			$("#dTVAHeader").show();
			$(".dcTVA").show();
		} else {
			$("#dTVAHeader").hide();
			$(".dcTVA").hide();
		}
		this.LoadDiscounturiInCombo();
		$.each(this.Articole, function (i, v) {            
			v.PutDataToForm();
        });
		
    };

    this.LoadFurnizoriInCombo = function (combo) {
		$(combo).find('option').remove();
        $.each(this.Furnizori, function (i, v) {
             $(combo).append("<option value=" + v.ID + ">" + v.Denumire + "</option>");
        });
    }
	
    this.LoadDiscounturiInCombo = function () {
		var ma = this.Discounturi;
		$.each(this.Articole, function (ia, va) {
			var combo = "#cmbArt" + va.Nrc + "Discount";
			$(combo).find('option').remove();
			$.each(ma, function (i, v) {
				if (v.IDF == $("#cmbFurnizor").val()) {
					$(combo).append("<option value=" + v.ID + ">" + v.Denumire + "</option>");					
				 }
			});
		});
    }
	
	
    /*END of methods*/
}

function Vanzare2() {
    /*properties*/
    this.IDF = 0;
	this.IDC = 0;
	this.CodP = "";
	this.DocTip = "";
    this.DocData = "";
    this.DocNr = "";
    this.Valoare = 0;
    this.Articole = [];
    this.Furnizori = new Array();	
	this.Eroare = "";
    /*END of properties*/

    /*methods*/
	this.Clear = function() {	
		this.IDF = 0;
		this.IDC = 0;
		this.CodP = "";	
		this.DocData = "";
	    this.DocNr = "";
	    this.Valoare = "";
		this.PutDataToForm();
	}
	    
	this.Salvez = function(runonsave) {
		var r = false;
		var mp = new Array();
		var mpa = new Array();
		var md = new Array()
				
		md = { s: "vanzreg2", 
			df: this.IDF,
			dt: this.DocTip,
			dd: this.DocData,
			dn: this.DocNr,
			dv: this.Valoare,
            dc: this.IDC,
			cs: $("#txtCodSec").val()};
		if (this.CodP.length > 0) {
			md.s = "vanzreg3";
			md["dp"] = this.CodP;
		}
				
		ClearAndHidePanel("pnlErr");
		ClearAndHidePanel("pnlMsg");
		
		MsgPannel("pnlMsg", "Înregistrez vanzarea.", true, false);
		var mt = this;
		$.post("../../lib/scripts/ws.php", md,
			function(data){
				ClearAndHidePanel("pnlErr");
				ClearAndHidePanel("pnlMsg");
				
				if (trim(data) == "OK") {
					MsgPannelCuButon("pnlMsg", "Cumpărătura a fost înregistrată.", false, true);
                    if (typeof(runonsave) != "undefined"){
                        eval(runonsave);
                    }
					mt.Clear();
                    r = true;
				} else {
					if (data.length == 0) {
						data = "O eroare a apărut la inregistrarea cumpărăturii!";
					}					
					ErrorPanel("pnlErr", data, false, true);
				}
				$("#captcha").attr("src", "../../lib/securimage/securimage_show.php?bg=9a999e&timestamp=" + new Date().getTime());
				$("#txtCodSec").val('');
		});			
		
		return r;
	}
	
	this.Validez = function() {
		var r = true;
		this.Eroare = "";
		
		if (this.IDF <= 0){
			this.Eroare += "Furnizorul nu este completat!<br/>";
			r = false;
		}
		
		if (this.Furnizori.length == 0 && this.IDC <= 0){
			this.Eroare += "Comisionul nu este completat!<br/>";
			r = false;
		}
		
		if (this.DocData.length == 0){
			this.Eroare += "Data cumpărăturii nu este completată!<br/>";
			r = false;
		}
		
		if (this.DocNr.length == 0){
			this.Eroare += "Numarul documentului nu este completat!<br/>";
			r = false;
		}
				
		if (this.Valoare.length <= 0){
			this.Eroare += "Valoarea cumpărăturii nu este completată!<br/>";
			r = false;
		} else {
			if (isNaN(this.Valoare)){
				this.Eroare += "Valoarea cumpărăturii nu este completată corect!<br/>";
				r = false;
			} else {
				if (parseFloat(this.Valoare) <= 0){
					this.Eroare += "Valoarea cumpărăturii trebuie să fie mai mare de 0!<br/>";
					r = false;
				}		
			}
		}
			
		if (r == true){
			if ($("#txtCodSec").val().length == 0){
				this.Eroare += "Codul de securitate nu este completat!<br/>";
				r = false;
			}
		}
		
		return r;
	}
		
	this.GetDataFromForm = function() {
        if (this.CodP.length > 0) {            
            this.CodP = $("#txtCodClient").val().toUpperCase();			
		} else {
            this.IDF = $("#cmbFurnizor").val();
		}        
        this.IDC = $("#cmbComision").val();		
		this.DocData = $("#txtDataDocument").val();
		this.DocNr = $("#txtNumarDocument").val();
		this.Valoare = $("#txtValoareDocument").val().replace(/\./g, "").replace(",", ".");
	};
	
	this.PutDataToForm = function() {
		if (this.Furnizori.length > 0) {
			$("#cmbFurnizor").val(this.IDF);
		} else {
			$("#cmbFurnizor").val(this.IDC);
			$("#txtCodClient").val(this.CodP);
		}
		$("#txtDataDocument").val(this.DocData);
		$("#txtNumarDocument").val(this.DocNr);
		$("#txtValoareDocument").val(this.Valoare);
	};

    this.LoadFurnizoriInCombo = function (combo) {
		$(combo).find('option').remove();
		$(combo).append("<option value=0>Selectează furnizorul!</option>");
        $.each(this.Furnizori, function (i, v) {
             $(combo).append("<option value=" + v.ID + ">" + v.Denumire + "</option>");
        });
    }	
	
	this.LoadDiscounturiInCombo = function (combo, pidf) {
		$(combo).find('option').remove();
		mld = this.Discounturi;
        $.each(mld, function (i, v) {
            if (v.IDF == pidf) {
                $(combo).append("<option value=" + v.ID + ">" + v.Denumire + "</option>");
            }            
        });
    }
    /*END of methods*/
}

function Furnizor(id, cod, denumire, descriere, url, mtt) {
    this.ID = id;
    this.Cod = cod;
    this.Denumire = denumire;
    this.Descriere = descriere;
    this.URL = url;
	this.Mtt = mtt;
}

function Discount(id, idf, cod, denumire) {
    this.ID = id;
    this.Cod = cod;
    this.Denumire = denumire;
	this.IDF = idf;
}

function Articol() {
    this.Nrc = 0;
    this.Denumire = "";
	this.Cantitate = 0;
    this.Valoare = 0;
	this.TVA = 0;
    this.ComisionID = 0;

    this.Draw = function () {
        var ms = '<div class="dcRow">' +
					'<div class="dcRowCol3" style="width: 30px; padding: 4px; text-align: right;" id="dArt' + this.Nrc + 'Nr"></div>' +
                    '<div class="dcRowCol3">' +
                        '<input id="txtArt' + this.Nrc + 'Denumire" type="text" class="txtDenumireArticol" maxlength="128"/>' +
                    '</div>' +
					'<!--<div class="dcRowCol4" style="width: 70px;">' +
                        '<input id="txtArt' + this.Nrc + 'Cantitate" type="text" class="numericInput" style="width: 60px;" maxlength="10" onkeypress="return numbersonly(this, event, 2)"/>' +
                    '</div>-->' +
                    '<div class="dcRowCol4">' +
                        '<input id="txtArt' + this.Nrc + 'Valoare" type="text" class="numericInput" style="width: 80px;" maxlength="10" onkeypress="return numbersonly(this, event, 2)"/>' +
                    '</div>' +
					'<div class="dcRowCol4 dcTVA">' +
                        '<input id="txtArt' + this.Nrc + 'TVA" type="text" class="numericInput" style="width: 80px;" maxlength="10" onkeypress="return numbersonly(this, event, 2)"/>' +
                    '</div>' +
                    '<div class="dcRowCol5">' +
                        '<select id="cmbArt' + this.Nrc + 'Discount"></select>' +
                    '</div>' +
                    '<div class="dcRowCol5" style="width: 20px;">' +
                        '<button style="background-color: red; font-weight= bold;" onclick="javascript: if(mv.StergArticol(' + this.Nrc + ')) mv.DrawArticole(\'#dContinutArticole\');">X</button>' +
                    '</div>' +
                '</div>';
        return ms;
    }
	
	this.GetDataFromForm = function() {
		this.Denumire = $("#txtArt" + this.Nrc + "Denumire").val();
		//this.Cantitate = $("#txtArt" + this.Nrc + "Cantitate").val();
		this.Valoare = $("#txtArt" + this.Nrc + "Valoare").val();
		this.TVA = $("#txtArt" + this.Nrc + "TVA").val();
		this.ComisionID = $("#cmbArt" + this.Nrc + "Discount").val();
	};
	
	this.PutDataToForm = function() {
		$("#dArt" + this.Nrc + "Nr").html(this.Nrc);
		$("#txtArt" + this.Nrc + "Denumire").val(this.Denumire);
		$("#txtArt" + this.Nrc + "Cantitate").val(this.Cantitate);
		$("#txtArt" + this.Nrc + "Valoare").val(this.Valoare);
		$("#txtArt" + this.Nrc + "TVA").val(this.TVA);
		$("#cmbArt" + this.Nrc + "Discount").val(this.ComisionID);
	};
}

/************************************************************************* 
 END of Classes
**************************************************************************/

/************************************************************************* 
 Crypt functions
**************************************************************************/

function md (str) {
    // http://kevin.vanzonneveld.net
    // +   original by: Webtoolkit.info (http://www.webtoolkit.info/)
    // + namespaced by: Michael White (http://getsprink.com)
    // +    tweaked by: Jack
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: Brett Zamir (http://brett-zamir.me)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: utf8_encode
    // *     example 1: md5('Kevin van Zonneveld');
    // *     returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
 
    var xl;
 
    var rotateLeft = function (lValue, iShiftBits) {
        return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
    };
 
    var addUnsigned = function (lX,lY) {
        var lX4,lY4,lX8,lY8,lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    };
 
    var _F = function (x,y,z) { return (x & y) | ((~x) & z); };
    var _G = function (x,y,z) { return (x & z) | (y & (~z)); };
    var _H = function (x,y,z) { return (x ^ y ^ z); };
    var _I = function (x,y,z) { return (y ^ (x | (~z))); };
 
    var _FF = function (a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _GG = function (a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _HH = function (a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _II = function (a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var convertToWordArray = function (str) {
        var lWordCount;
        var lMessageLength = str.length;
        var lNumberOfWords_temp1=lMessageLength + 8;
        var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
        var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
        var lWordArray=new Array(lNumberOfWords-1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while ( lByteCount < lMessageLength ) {
            lWordCount = (lByteCount-(lByteCount % 4))/4;
            lBytePosition = (lByteCount % 4)*8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount)<<lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount-(lByteCount % 4))/4;
        lBytePosition = (lByteCount % 4)*8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
        lWordArray[lNumberOfWords-2] = lMessageLength<<3;
        lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
        return lWordArray;
    };
 
    var wordToHex = function (lValue) {
        var wordToHexValue="",wordToHexValue_temp="",lByte,lCount;
        for (lCount = 0;lCount<=3;lCount++) {
            lByte = (lValue>>>(lCount*8)) & 255;
            wordToHexValue_temp = "0" + lByte.toString(16);
            wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length-2,2);
        }
        return wordToHexValue;
    };
 
    var x=[],
        k,AA,BB,CC,DD,a,b,c,d,
        S11=7, S12=12, S13=17, S14=22,
        S21=5, S22=9 , S23=14, S24=20,
        S31=4, S32=11, S33=16, S34=23,
        S41=6, S42=10, S43=15, S44=21;
 
    str = this.utf8_encode(str);
    x = convertToWordArray(str);
    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
    
    xl = x.length;
    for (k=0;k<xl;k+=16) {
        AA=a; BB=b; CC=c; DD=d;
        a=_FF(a,b,c,d,x[k+0], S11,0xD76AA478);
        d=_FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
        c=_FF(c,d,a,b,x[k+2], S13,0x242070DB);
        b=_FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
        a=_FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
        d=_FF(d,a,b,c,x[k+5], S12,0x4787C62A);
        c=_FF(c,d,a,b,x[k+6], S13,0xA8304613);
        b=_FF(b,c,d,a,x[k+7], S14,0xFD469501);
        a=_FF(a,b,c,d,x[k+8], S11,0x698098D8);
        d=_FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
        c=_FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
        b=_FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
        a=_FF(a,b,c,d,x[k+12],S11,0x6B901122);
        d=_FF(d,a,b,c,x[k+13],S12,0xFD987193);
        c=_FF(c,d,a,b,x[k+14],S13,0xA679438E);
        b=_FF(b,c,d,a,x[k+15],S14,0x49B40821);
        a=_GG(a,b,c,d,x[k+1], S21,0xF61E2562);
        d=_GG(d,a,b,c,x[k+6], S22,0xC040B340);
        c=_GG(c,d,a,b,x[k+11],S23,0x265E5A51);
        b=_GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
        a=_GG(a,b,c,d,x[k+5], S21,0xD62F105D);
        d=_GG(d,a,b,c,x[k+10],S22,0x2441453);
        c=_GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
        b=_GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
        a=_GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
        d=_GG(d,a,b,c,x[k+14],S22,0xC33707D6);
        c=_GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
        b=_GG(b,c,d,a,x[k+8], S24,0x455A14ED);
        a=_GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
        d=_GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
        c=_GG(c,d,a,b,x[k+7], S23,0x676F02D9);
        b=_GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
        a=_HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
        d=_HH(d,a,b,c,x[k+8], S32,0x8771F681);
        c=_HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
        b=_HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
        a=_HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
        d=_HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
        c=_HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
        b=_HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
        a=_HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
        d=_HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
        c=_HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
        b=_HH(b,c,d,a,x[k+6], S34,0x4881D05);
        a=_HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
        d=_HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
        c=_HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
        b=_HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
        a=_II(a,b,c,d,x[k+0], S41,0xF4292244);
        d=_II(d,a,b,c,x[k+7], S42,0x432AFF97);
        c=_II(c,d,a,b,x[k+14],S43,0xAB9423A7);
        b=_II(b,c,d,a,x[k+5], S44,0xFC93A039);
        a=_II(a,b,c,d,x[k+12],S41,0x655B59C3);
        d=_II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
        c=_II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
        b=_II(b,c,d,a,x[k+1], S44,0x85845DD1);
        a=_II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
        d=_II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
        c=_II(c,d,a,b,x[k+6], S43,0xA3014314);
        b=_II(b,c,d,a,x[k+13],S44,0x4E0811A1);
        a=_II(a,b,c,d,x[k+4], S41,0xF7537E82);
        d=_II(d,a,b,c,x[k+11],S42,0xBD3AF235);
        c=_II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
        b=_II(b,c,d,a,x[k+9], S44,0xEB86D391);
        a=addUnsigned(a,AA);
        b=addUnsigned(b,BB);
        c=addUnsigned(c,CC);
        d=addUnsigned(d,DD);
    }
 
    var temp = wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);
 
    return temp.toLowerCase();
}

function utf8_encode ( argString ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Webtoolkit.info (http://www.webtoolkit.info/)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: sowberry
    // +    tweaked by: Jack
    // +   bugfixed by: Onno Marsman
    // +   improved by: Yves Sucaet
    // +   bugfixed by: Onno Marsman
    // +   bugfixed by: Ulrich
    // *     example 1: utf8_encode('Kevin van Zonneveld');
    // *     returns 1: 'Kevin van Zonneveld'
 
    var string = (argString+''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
 
    var utftext = "";
    var start, end;
    var stringl = 0;
 
    start = end = 0;
    stringl = string.length;
    for (var n = 0; n < stringl; n++) {
        var c1 = string.charCodeAt(n);
        var enc = null;
 
        if (c1 < 128) {
            end++;
        } else if (c1 > 127 && c1 < 2048) {
            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
        } else {
            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);
        }
        if (enc !== null) {
            if (end > start) {
                utftext += string.substring(start, end);
            }
            utftext += enc;
            start = end = n+1;
        }
    }
 
    if (end > start) {
        utftext += string.substring(start, string.length);
    }
 
    return utftext;
}

function hs(msg)
{
    // constants [§4.2.1]
    var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6];


    // PREPROCESSING 
 
    msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1]

    // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1]
    var l = msg.length/4 + 2;  // length (in 32-bit integers) of msg + ‘1’ + appended length
    var N = Math.ceil(l/16);   // number of 16-integer-blocks required to hold 'l' ints
    var M = new Array(N);
    for (var i=0; i<N; i++) {
        M[i] = new Array(16);
        for (var j=0; j<16; j++) {  // encode 4 chars per integer, big-endian encoding
            M[i][j] = (msg.charCodeAt(i*64+j*4)<<24) | (msg.charCodeAt(i*64+j*4+1)<<16) | 
                      (msg.charCodeAt(i*64+j*4+2)<<8) | (msg.charCodeAt(i*64+j*4+3));
        }
    }
    // add length (in bits) into final pair of 32-bit integers (big-endian) [5.1.1]
    // note: most significant word would be (len-1)*8 >>> 32, but since JS converts
    // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators
    M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]);
    M[N-1][15] = ((msg.length-1)*8) & 0xffffffff;

    // set initial hash value [§5.3.1]
    var H0 = 0x67452301;
    var H1 = 0xefcdab89;
    var H2 = 0x98badcfe;
    var H3 = 0x10325476;
    var H4 = 0xc3d2e1f0;

    // HASH COMPUTATION [§6.1.2]

    var W = new Array(80); var a, b, c, d, e;
    for (var i=0; i<N; i++) {

        // 1 - prepare message schedule 'W'
        for (var t=0;  t<16; t++) W[t] = M[i][t];
        for (var t=16; t<80; t++) W[t] = ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);

        // 2 - initialise five working variables a, b, c, d, e with previous hash value
        a = H0; b = H1; c = H2; d = H3; e = H4;

        // 3 - main loop
        for (var t=0; t<80; t++) {
            var s = Math.floor(t/20); // seq for blocks of 'f' functions and 'K' constants
            var T = (ROTL(a,5) + f(s,b,c,d) + e + K[s] + W[t]) & 0xffffffff;
            e = d;
            d = c;
            c = ROTL(b, 30);
            b = a;
            a = T;
        }

        // 4 - compute the new intermediate hash value
        H0 = (H0+a) & 0xffffffff;  // note 'addition modulo 2^32'
        H1 = (H1+b) & 0xffffffff; 
        H2 = (H2+c) & 0xffffffff; 
        H3 = (H3+d) & 0xffffffff; 
        H4 = (H4+e) & 0xffffffff;
    }

    return H0.toHexStr() + H1.toHexStr() + H2.toHexStr() + H3.toHexStr() + H4.toHexStr();
}

//
// function 'f' [§4.1.1]
//
function f(s, x, y, z) 
{
    switch (s) {
    case 0: return (x & y) ^ (~x & z);           // Ch()
    case 1: return x ^ y ^ z;                    // Parity()
    case 2: return (x & y) ^ (x & z) ^ (y & z);  // Maj()
    case 3: return x ^ y ^ z;                    // Parity()
    }
}

//
// rotate left (circular left shift) value x by n positions [§3.2.5]
//
function ROTL(x, n)
{
    return (x<<n) | (x>>>(32-n));
}

//
// extend Number class with a tailored hex-string method 
//   (note toString(16) is implementation-dependant, and 
//   in IE returns signed numbers when used on full words)
//
Number.prototype.toHexStr = function()
{
    var s="", v;
    for (var i=7; i>=0; i--) { v = (this>>>(i*4)) & 0xf; s += v.toString(16); }
    return s;
}

/************************************************************************* 
 END of Crypt functions
**************************************************************************/

