
Broco={};Broco.Config={};Broco.Config.Debug={enabled:true,doExtraChecks:false};Broco.ClassBase=function ClassBase(){};Broco.ClassBase.prototype.construct=function(){};Broco.ClassBase.extend=function(def){var classDef=function(){if(arguments[0]!==Broco.ClassBase){this.construct.apply(this,arguments);}};var proto=new this(Broco.ClassBase);var superClass=this.prototype;for(var n in def){var item=def[n];if(item instanceof Function)item.$=superClass;proto[n]=item;}
classDef.prototype=proto;classDef.extend=this.extend;return classDef;};
Broco.Storage=Broco.ClassBase.extend({construct:function()
{this._elements={};this._tags={};this._count=0;},clean:function(mode,tags)
{mode=mode||"all";tags=tags||[];if(Broco.Config.Debug.doExtraChecks){if(typeof mode!="string"){throw new TypeError("The mode parameter must be string");}
for(var i=0;i<tags.length;i++){if(typeof tags[i]!="string"){throw new TypeError("Tags must be strings");}}}
var ids=[];switch(mode){case'all':this._elements={};this._tags={};this._count=0;break;case'matchingAllTags':this.remove(this.getIdsMatchingAllTags(tags));break;case'notMatchingAllTags':this.remove(this.getIdsNotMatchingAllTags(tags));break;case'matchingAnyTags':this.remove(this.getIdsMatchingAnyTags(tags));break;case'notMatchingAnyTags':this.remove(this.getIdsNotMatchingAnyTags(tags));break;default:throw new Error("The clean mode \""+mode+"\" is invalid");}},getIds:function()
{var ids=[];for(var i in this._elements){ids.push(i);}
return ids;},getIdsMatchingAnyTags:function(tags)
{tags=tags||[];var ids=[];var idHash={};for(var i=0;i<tags.length;i++){for(var id in this._tags[tags[i]]){idHash[id]=true;}}
for(var id in idHash){ids.push(id);}
return ids;},getIdsMatchingAllTags:function(tags)
{tags=tags||[];var ids=[];var idHash={};for(var i=0;i<tags.length;i++){for(var id in this._tags[tags[i]]){if(!idHash[id]){idHash[id]=1;}else{idHash[id]++;}}}
for(var id in idHash){if(idHash[id]==tags.length){ids.push(id);}}
return ids;},getIdsNotMatchingAnyTags:function(tags)
{tags=tags||[];var ids=[];var idHash={};for(tag in this.tags){for(id in this.tags[tag]){idHash[this.tags[tag][id]]=0;for(var i=0;i<tags.length;i++){if(tags[i]==tag){idHash[this.tags[tag][id]]++;break;}}}}
for(var id in idHash){if(idHash[id]<tags.length){ids.push(id);}}
return ids;throw new Error("Not implemented yet");},getIdsNotMatchingAllTags:function(tags)
{tags=tags||[];var ids=[];var idHash={};for(tag in this.tags){for(id in this.tags[tag]){idHash[this.tags[tag][id]]=true;}}
for(var i=0;i<tags.length;i++){for(var id in this._tags[tags[i]]){delete idHash[id];}}
for(var id in idHash){ids.push(id);}
return ids;},getTags:function()
{var tags=[];for(tag in this._tags){tags.push(tag);}
return tags;},load:function(id)
{if(typeof id=="number"){id=id+"";}
if(this._elements[id]){return this._elements[id].data;}else{return null;}},remove:function(id)
{if(id instanceof Array){for(var i=0;i<id.length;i++){this.remove(id[i]);}}
if(typeof id=="number"){id=id+"";}
if(this._elements[id]){for(var i=0;i<this._elements[id].tags.lenth;i++){delete this._tags[this._elements[id].tags[i]][id];}
delete this._elements[id];this._count--;}},save:function(data,id,tags)
{if(typeof id=="number")
id=id+"";this.remove(id);tags=tags||[];if(Broco.Config.Debug.doExtraChecks){if(!(typeof id=="string")){throw new TypeError("The id parameter must be string ("+typeof(id)+" given)");}
for(var i=0;i<tags.length;i++){if(typeof tags[i]!="string"){throw new TypeError("Tags must be strings");}}}
this._elements[id]={"data":data,"tags":tags};for(var i=0;i<tags.length;i++){if(!this._tags[tags[i]]){this._tags[tags[i]]={};}
this._tags[tags[i]][id]=true;}
this._count++;},test:function(id)
{if(typeof id=="number")
id=id+"";return typeof this._elements[id]!="undefined";},getCount:function()
{return this._count;},isEmpty:function()
{return this._count==0;}});
Broco.HashMap=Broco.ClassBase.extend({construct:function(map)
{this._map=map;this._storage=new Broco.Storage();this._autoincrementId=1;this._ids=[];},addElement:function(element)
{var tags=[];for(var i=0;i<this._map.length;i++){var field=this._map[i];if(element[field]){tags.push(this._getStorageTag(field,element[field]));}}
this._storage.save(element,this._autoincrementId,tags);this._ids.push(this._autoincrementId);this._autoincrementId++;return this;},removeElement:function(index)
{if(typeof this._ids[index]=="undefined"){throw new RangeError("Element with index "+index+" not found");}
this._storage.remove(this._ids[index]);this._ids.splice(index,1);return this;},removeElementsBy:function(field,value)
{var tags=[];if(value instanceof Array){for(var i=0;i<value.length;i++){tags.push(this._getStorageTag(field,value[i]));}}else{tags.push(this._getStorageTag(field,value));}
var idsToRemove={};for(i in this._storage.getIdsMatchingAllTags(tags)){idsToRemove[i]=true;}
this._storage.clean("matchingAnyTags",tags);for(var i=0;i<this._ids.length;i++){if(typeof idsToRemove[this._ids[i]]!="undefined"){this._ids.splice(i,1);}}
return this;},removeAll:function()
{this._storage.clean();this._ids=[];return this;},toArray:function()
{var elements=[];for(var i=0,max=this.getCount();i<max;i++){elements.push(this.getElement(i));}
return elements;},getElement:function(index)
{if(this._storage.test(this._ids[index])){return this._storage.load(this._ids[index]);}else{throw new RangeError("Element with index "+index+" not found");}},_getElementsIdsBy:function(field,value)
{var tags=[];if(value instanceof Array){for(var i=0;i<value.length;i++){tags.push(this._getStorageTag(field,value[i]));}}else{tags.push(this._getStorageTag(field,value));}
return this._storage.getIdsMatchingAnyTags(tags);},getElementBy:function(field,value)
{var ids=this._getElementsIdsBy(field,value);if(ids.length>0){return this._storage.load(ids[0]);}else{throw new Error("No element with field \""+field+"\" and value = \""+value+"\"");}},getElementsBy:function(field,value)
{var ids=this._getElementsIdsBy(field,value);var elements=[];for(var i=0;i<ids.length;i++){elements.push(this._storage.load(ids[i]));}
return elements;},getCountElementsBy:function(field,value)
{return this._getElementsIdsBy(field,value).length;},_getElementsIdsByMask:function(mask)
{var tags=[];for(var i in mask){tags.push(this._getStorageTag(i,mask[i]));}
return this._storage.getIdsMatchingAllTags(tags);},getElementsByMask:function(mask)
{var ids=this._getElementsIdsByMask(mask);var elements=[];for(var i=0;i<ids.length;i++){elements.push(this._storage.load(ids[i]));}
return elements;},getCountElementsByMask:function(mask)
{return this._getElementsIdsByMask(mask).length;},testElement:function(index)
{return index<this.getCount();},testElementBy:function(field,value)
{return this._storage.getIdsMatchingAnyTags([this._getStorageTag(field,value)]).length>0;},testElementsBy:function(field,value)
{var tags=[];if(value instanceof Array){for(var i=0;i<value.length;i++){tags.push(this._getStorageTag(field,value[i]));}}else{tags.push(this._getStorageTag(field,value));}
return this._storage.getIdsMatchingAnyTags(tags).length>0;},getCount:function()
{return this._storage.getCount();},isEmpty:function()
{return this._storage.isEmpty();},_getStorageTag:function(field,value)
{field=field+"";value=value+"";return"\""+field.replace(/"/,"\\\"")+"\":\""+value.replace(/"/,"\\\"")+"\"";},clone:function()
{var map=[];for(var i=0,max=this._map.length;i<max;i++){map.push(this._map[i]);}
var hashMap=new Broco.HashMap(map);for(var i=0,max=this.getCount();i<max;i++){hashMap.addElement(this.getElement(i));}
return hashMap;}});
Broco.Config.Debug.doExtraChecks=true;
Broco.TraderCalc=Broco.ClassBase.extend({construct:function(container,config,locale)
{this.container=typeof container=="string"?jQuery('#'+container):jQuery(container);this._config=Broco.TraderCalc.DefaultConfig||{};this.parseConfig(config||{});this._locale=locale;if(!this._locale){var localesCounter=0;for(locale in Broco.TraderCalc.Languages){localesCounter++;}
if(localesCounter==1){this._locale=locale;}else if(localesCounter>1){throw new Error("Translate language cannot be guessed because there is more than one translate. Specify it explicitly in constructor.");}}
if(typeof Broco.TraderCalc.Languages[this._locale]=="undefined"){throw new Error("Language translate for locale \""+this._locale+"\" is not found");}
this._install();this.fieldsList=jQuery('dl.broco-tradercalc-fields',this.container);this._tools=new Broco.HashMap(["id","symbol","group_id"]);this._groups=new Broco.HashMap(["id","category_id","account_type_id"]);this._categories=new Broco.HashMap(["id","name"]);this._accountTypes=new Broco.HashMap(["id"]);this._quotes=new Broco.HashMap(["trading_tools_id"]);this._toolConversionSymbol=null;this._marginConversionSymbol=null;this._openPriceCleanValue="";this._closePriceCleanValue="";this._toolConversionRateCleanValue="";this._marginConversionRateCleanValue="";this._extendedFieldsCategory;this._extendedFieldsSymbol;this._extendedFieldsToolConversionSymbol;this._extendedFieldsMarginConversionSymbol;this._toolsLoadedFirst=false;this._quotesLoadedFirst=false;this.init();},_install:function()
{this.container.empty();jQuery("<dl class=\"broco-tradercalc-fields\">\n"+"<dt>"+this._getText("FieldTitle_AccountType")+":</dt>\n"+"<dd>"+"<select name=\"account_type\">"+"</select>"+"</dd>\n"+"<dt>"+this._getText("FieldTitle_Category")+":</dt>\n"+"<dd>"+"<select name=\"category\">"+"</select>"+"</dd>\n"+"<dt>"+this._getText("FieldTitle_TradingTool")+":</dt>\n"+"<dd><select name=\"symbol\"></select></dd>\n"+"<dt>"+this._getText("FieldTitle_DealType")+":</dt>\n"+"<dd><select name=\"type\"><option>buy</option><option>sell</option></select></dd>\n"+"<dt>"+this._getText("FieldTitle_Lots")+":</dt>\n"+"<dd><input type=\"text\" name=\"lots\" value=\"1\" maxlength=\"8\" /></dd>\n"+"<dt>"+this._getText("FieldTitle_OpenPrice")+":</dt>\n"+"<dd><input type=\"text\" name=\"open_price\" maxlength=\"9\" /></dd>\n"+"<dt>"+this._getText("FieldTitle_ClosePrice")+":</dt>\n"+"<dd><input type=\"text\" name=\"close_price\" maxlength=\"9\" /></dd>\n"+"<dt>"+this._getText("FieldTitle_Balance")+":</dt>\n"+"<dd><input type=\"text\" name=\"balance\" value=\"0\" maxlength=\"8\" /></dd>\n"+"<dt>"+this._getText("FieldTitle_DepositCurrency")+":</dt>\n"+"<dd><select name=\"deposit_currency\"><option>USD</option><option>EUR</option><option>RUB</option></select></dd>\n"+"</dl>"+"<div class=\"broco-tradercalc-submit\"><input type=\"button\" value=\""+this._getText("Button_Calculate")+"\" disabled=\"disabled\" /></div>"+"<div class=\"broco-tradercalc-result\"></div>").appendTo(this.container);},init:function()
{var traderCalc=this;this._requestSpecificationsAsJson();this._requestQuotesAsJson();window.setInterval(function(){traderCalc._requestSpecificationsAsJson()},this.getOption("updateSpecificationsInterval"));window.setInterval(function(){traderCalc._requestQuotesAsJson()},this.getOption("updateQuotesInterval"));jQuery("input[type='button']",this.container).bind("click",function(e){traderCalc._onCalculateClick(e);});jQuery("input[type='text']",this.fieldsList).bind("keypress",function(e){traderCalc._onInputKeyPress(e);});this._getFormField("account_type").bind("change",function(e){traderCalc._onAccountTypeChange(e);});this._getFormField("category").bind("change",function(e){traderCalc._onCategoryChange(e);});this._getFormField("symbol").bind("change",function(e){traderCalc._onSymbolChange(e);});this._getFormField("type").bind("change",function(e){traderCalc._onDealTypeChange(e);});this._getFormField("deposit_currency").bind("change",function(e){traderCalc._onDepositCurrencyChange(e);});},parseConfig:function(config)
{for(var key in config){switch(key){case'specificationsUri':case'quotesUri':case'calculateUri':case'updateSpecificationsInterval':case'updateQuotesInterval':case'jsonp':this.setOption(key,config[key]);break;default:throw new Error("Unknown option parameter \""+key+"\"");}}},setOption:function(option,value){this._config[option]=value;},getOption:function(option)
{if(typeof this._config[option]!="undefined"){var value=this._config[option];return typeof value=="function"?value(this):value;}else{throw new Error("Config option "+option+" is not defined");}},_requestSpecificationsAsJson:function()
{var traderCalc=this;jQuery.ajax({type:"GET",url:this._getAjaxUri('specifications-list'),success:function(data){traderCalc._loadSpecificationsFromJsonData(data);},jsonp:this.getOption("jsonp")?"jsonp_callback":"",dataType:'json'+(this.getOption("jsonp")?'p':'')});},_requestQuotesAsJson:function()
{var traderCalc=this;jQuery.ajax({type:"GET",url:this._getAjaxUri('quotes-list'),success:function(data){traderCalc._loadQuotesFromJsonData(data);},jsonp:this.getOption("jsonp")?"jsonp_callback":"",dataType:'json'+(this.getOption("jsonp")?'p':'')});},_requestResultAsJson:function()
{var data=this._getFormData();var traderCalc=this;jQuery.ajax({type:"GET",url:this._getAjaxUri('calculate'),data:data,success:function(data){traderCalc._loadCalculateResultFromJsonData(data);},jsonp:this.getOption("jsonp")?"jsonp_callback":"",dataType:'json'+(this.getOption("jsonp")?'p':'')});},_updateAccountTypeSelect:function()
{var select=this._getFormField("account_type");var oldValue=select.val();select.empty();for(var i=0,max=this._accountTypes.getCount();i<max;i++){var accountType=this._accountTypes.getElement(i);jQuery("<option value=\""+accountType.id+"\">"+accountType.title+"</option>").appendTo(select);}
if(oldValue!=null){select.val(oldValue);}},_updateCategorySelect:function()
{var select=this._getFormField("category");var oldValue=select.val();select.empty();for(var i=0,max=this._categories.getCount();i<max;i++){var category=this._categories.getElement(i);if(this._groups.getCountElementsByMask({'category_id':category.id,'account_type_id':this._getFormFieldValue('account_type')})>0){jQuery("<option value=\""+category.name+"\">"+category.title+"</option>").appendTo(select);}}
if(oldValue!=null){select.val(oldValue);}},_updateSymbolSelect:function()
{var category=this._categories.getElementBy("name",this._getFormFieldValue("category"));var select=this._getFormField("symbol");var oldValue=select.val();select.empty();var groups=this._groups.getElementsByMask({"category_id":category.id,"account_type_id":this._getFormFieldValue("account_type")});for(var gi=0;gi<groups.length;gi++){if(groups.length>1){var symbolsOptGroup=jQuery("<optgroup></optgroup>");symbolsOptGroup.attr("label",groups[gi].name);symbolsOptGroup.appendTo(select);}else{var symbolsOptGroup=select;}
var symbols=this._tools.getElementsBy("group_id",groups[gi].id);for(var si=0;si<symbols.length;si++){var symbolOption=jQuery("<option value=\""+symbols[si].symbol+"\">"+symbols[si].symbol+"</option>").appendTo(select);symbolOption.appendTo(symbolsOptGroup);}}
if(oldValue!=null){select.val(oldValue);}},_updatePrices:function()
{var symbol=this._getFormFieldValue("symbol");var quote=this._getQuote(symbol);if(!quote){return;}
var type=this._getFormFieldValue("type");var openPrice=jQuery("input[name='open_price']",this.fieldsList);var closePrice=jQuery("input[name='close_price']",this.fieldsList);var digits=this._tools.getElementBy("symbol",symbol).digits;if(openPrice.val()==this._openPriceCleanValue){openPrice.val(this._numberFormat(type=="buy"?quote.ask:quote.bid,digits,".",""));this._openPriceCleanValue=openPrice.val();}
if(closePrice.val()==this._closePriceCleanValue){closePrice.val(this._numberFormat(type=="buy"?quote.bid:quote.ask,digits,".",""));this._closePriceCleanValue=closePrice.val();}},_updateConversionSymbols:function()
{var symbol=this._getFormFieldValue("symbol");var depositCurrency=this._getFormFieldValue("deposit_currency");if(symbol!=null){var toolCurrency=this._getToolCurrency(symbol);if(toolCurrency!=depositCurrency){this._toolConversionSymbol=this._getBestConversionSymbol(toolCurrency,depositCurrency);}else{this._toolConversionSymbol=null;}
var marginCurrency=this._getMarginCurrency(symbol);if(marginCurrency!=depositCurrency){this._marginConversionSymbol=this._getBestConversionSymbol(marginCurrency,depositCurrency);}else{this._marginConversionSymbol=null;}}else{this._marginConversionSymbol=null;}},_updateConversionRates:function()
{var toolConversionRate=this._getFormField("tool_conversion_rate");if(toolConversionRate.val()==this._toolConversionRateCleanValue){var quote=this._toolConversionSymbol?this._getCalculatedQuote(this._toolConversionSymbol):null;var digits=this._getQuoteDigits(this._toolConversionSymbol);toolConversionRate.val(quote?this._numberFormat(quote.bid,digits,".",""):"");this._toolConversionRateCleanValue=toolConversionRate.val();}
var marginConversionRate=this._getFormField("margin_conversion_rate");if(marginConversionRate.val()==this._marginConversionRateCleanValue){var quote=this._marginConversionSymbol?this._getCalculatedQuote(this._marginConversionSymbol):null;var digits=this._getQuoteDigits(this._marginConversionSymbol);marginConversionRate.val(quote?this._numberFormat(quote.ask,digits,".",""):"");this._marginConversionRateCleanValue=marginConversionRate.val();}},_updateExtendedFields:function()
{var traderCalc=this;var category=this._getFormFieldValue("category");var symbol=this._getFormFieldValue("symbol");if(this._extendedFieldsCategory==category&&this._extendedFieldsSymbol==symbol&&this._extendedFieldsToolConversionSymbol==this._toolConversionSymbol){return;}
jQuery("dd select[name='deposit_currency']",this.fieldsList).parent().nextAll().remove();if(symbol){var toolCurrency=this._getToolCurrency(this._getFormFieldValue("symbol"));if(this._getFormFieldValue("deposit_currency")!=toolCurrency){jQuery("<dt>"+this._getText("FieldTitle_ToolConversionRate",{'symbol':this._toolConversionSymbol?this._toolConversionSymbol:"..."})+":</dt>"+"<dd><input type=\"text\" name=\"tool_conversion_rate\" value=\""+(this._toolConversionSymbol?this._toolConversionRateCleanValue:"")+"\" maxlength=\"9\" title=\""+this._getText("FieldHint_ToolConversionRate")+"\" /></dd>").appendTo(this.fieldsList);jQuery("input[type='text'][name='tool_conversion_rate']",this.fieldsList).bind("keypress",function(e){traderCalc._onInputKeyPress(e);});}
var marginCurrency=this._getMarginCurrency(this._getFormFieldValue("symbol"));if(this._getFormFieldValue("deposit_currency")!=marginCurrency){jQuery("<dt>"+this._getText("FieldTitle_MarginConversionRate",{'symbol':this._marginConversionSymbol?this._marginConversionSymbol:"..."})+":</dt>"+"<dd><input type=\"text\" name=\"margin_conversion_rate\" value=\""+(this._marginConversionSymbol?this._marginConversionRateCleanValue:"")+"\" maxlength=\"9\" title=\""+this._getText("FieldHint_MarginConversionRate")+"\" /></dd>").appendTo(this.fieldsList);jQuery("input[type='text'][name='margin_conversion_rate']",this.fieldsList).bind("keypress",function(e){traderCalc._onInputKeyPress(e);});}}
if(category=="forex"){jQuery("<dt>"+this._getText("FieldTitle_Expander")+":</dt>"+"<dd><select name=\"expander\"></select></dd>").appendTo(this.fieldsList);var expander=this._getFormField("expander");values=[1,2,3,5,10,15,20,25,33,50,100,200];for(i=0;i<values.length;i++){jQuery("<option value=\""+values[i]+"\">1:"+values[i]+"</option>").appendTo(expander);}}
this._extendedFieldsCategory=category;this._extendedFieldsSymbol=symbol;this._extendedFieldsToolConversionSymbol=this._toolConversionSymbol;},_clearResults:function()
{jQuery('.broco-tradercalc-result',this.container).empty();},_clearPrices:function()
{this._openPriceCleanValue="";this._closePriceCleanValue="";this._getFormField("open_price").val("");this._getFormField("close_price").val("");},_clearLots:function()
{this._getFormField("lots").val("1");},_getAjaxUri:function(action)
{switch(action){case'quotes-list':return this.getOption("quotesUri");case'specifications-list':return this.getOption("specificationsUri");case'calculate':return this.getOption("calculateUri");default:throw new Error("Unknown action \""+action+"\"");}},_getFormData:function()
{var data={'account_type_id':this._getFormFieldValue("account_type"),'category':this._getFormFieldValue("category"),'symbol':this._getFormFieldValue("symbol"),'type':this._getFormFieldValue("type"),'lots':this._getFormFieldValue("lots"),'open_price':this._getFormFieldValue("open_price"),'close_price':this._getFormFieldValue("close_price"),'balance':this._getFormFieldValue("balance"),'deposit_currency':this._getFormFieldValue("deposit_currency"),'tool_conversion_rate':this._getFormFieldValue("tool_conversion_rate")!=null?this._getFormFieldValue("tool_conversion_rate"):1,'tool_conversion_symbol':this._toolConversionSymbol,'margin_conversion_rate':this._getFormFieldValue("margin_conversion_rate")!=null?this._getFormFieldValue("margin_conversion_rate"):1,'margin_conversion_symbol':this._marginConversionSymbol};var fieldsToFixNumbers=['lots','open_price','close_price','balance','tool_conversion_rate','margin_conversion_rate'];for(var i=0;i<fieldsToFixNumbers.length;i++){data[fieldsToFixNumbers[i]]=this._fixInvalidNumber(data[fieldsToFixNumbers[i]]);}
if(data.category=="forex"){data.expander=this._getFormFieldValue("expander");}
return data;},_getFormField:function(fieldName)
{switch(fieldName){case'account_type':return jQuery('select[name="account_type"]',this.fieldsList);case'category':return jQuery('select[name="category"]',this.fieldsList);case'symbol':return jQuery('select[name="symbol"]',this.fieldsList);case'type':return jQuery('select[name="type"]',this.fieldsList);case'lots':return jQuery('input[name="lots"]',this.fieldsList);case'open_price':return jQuery('input[name="open_price"]',this.fieldsList);case'close_price':return jQuery('input[name="close_price"]',this.fieldsList);case'expander':return jQuery('select[name="expander"]',this.fieldsList);case'balance':return jQuery('input[name="balance"]',this.fieldsList);case'deposit_currency':return jQuery('select[name="deposit_currency"]',this.fieldsList);case'tool_conversion_rate':return jQuery('input[name="tool_conversion_rate"]',this.fieldsList);case'margin_conversion_rate':return jQuery('input[name="margin_conversion_rate"]',this.fieldsList);default:throw new Error("Unknown form field "+fieldName);}},_getFormFieldValue:function(field)
{return this._getFormField(field).val();},_getQuote:function(symbol)
{try{var quote=this._quotes.getElementBy("trading_tools_id",this._tools.getElementBy("symbol",symbol).id);return quote;}catch(e){return null;}},_getCalculatedQuote:function(symbol)
{var pair=this._parseCurrencyPair(symbol);var path=this._getCurrencyPath(pair.primary,pair.secondary,this._getCurrencyHash());if(path!=null){var quote={"bid":1,"ask":1};var currency=pair.primary;for(var i=0;i<path.length;i++){var _symbol=path[i];var _pair=this._parseCurrencyPair(_symbol);var _quote=this._getQuote(_symbol);if(_pair.primary==currency){quote.bid*=_quote.bid;quote.ask*=_quote.ask;currency=_pair.secondary;}else{quote.bid/=_quote.bid;quote.ask/=_quote.ask;currency=_pair.primary;}}
return quote;}else{return null;}},_getCurrencyPath:function(source,target,currencyHash,usedCurrencies,length)
{usedCurrencies=usedCurrencies||new Broco.HashMap(["currency"]);length=length||0;var bestResult={"path":null,"length":null};if(source==target){return[];}
if(length<2){for(var dir=0;dir<=1;dir++){var pairs=currencyHash.getElementsBy(dir==0?"primary":"secondary",source);for(var i=0;i<pairs.length;i++){if(usedCurrencies.testElementBy("currency",pairs[i][dir==0?"secondary":"primary"])){continue;}
var result;if(pairs[i][dir==0?"secondary":"primary"]!=target){result=this._getCurrencyPath(pairs[i][dir==0?"secondary":"primary"],target,currencyHash,usedCurrencies.clone().addElement({"currency":source}),length+1);if(result.path!=null){result.path.unshift(dir==0?(source+pairs[i].secondary):(pairs[i].primary+source));result.length+=length;}}else{result={"path":[dir==0?(source+pairs[i].secondary):(pairs[i].primary+source)],"length":length+1};}
if(result.path!==null&&(bestResult.length===null||result.length<bestResult.length)){bestResult=result;}}}}
return length==0?bestResult.path:bestResult;},_parseCurrencyPair:function(symbol)
{var matches=symbol.match(/^([a-z]{3})([a-z]{3})$/i);if(matches){return{"primary":matches[1],"secondary":matches[2]};}else{return null;}},_getToolCurrency:function(symbol)
{return this._tools.getElementBy("symbol",symbol).currency;},_getMarginCurrency:function(symbol)
{return this._tools.getElementBy("symbol",symbol).margin_currency;},_getCurrencyHash:function()
{var currencyHash=new Broco.HashMap(["primary","secondary"]);var groups=this._groups.getElementsBy("category_id",this._categories.getElementBy("name","forex").id);for(var grpIdx=0;grpIdx<groups.length;grpIdx++){var tools=this._tools.getElementsBy("group_id",groups[grpIdx].id)
for(var symIdx=0;symIdx<tools.length;symIdx++){var tool=tools[symIdx];var quote=this._getQuote(tool.symbol);var pair=this._parseCurrencyPair(tool.symbol);if(quote&&pair){currencyHash.addElement({"primary":pair.primary,"secondary":pair.secondary,"rate":quote.bid});}}}
return currencyHash;},_getBestConversionSymbol:function(currencyFrom,currencyTo)
{var directPair=currencyFrom+currencyTo;if(this._tools.testElementBy("symbol",directPair)){return directPair;}
var reversedPair=currencyTo+currencyFrom;if(this._tools.testElementBy("symbol",reversedPair)){return reversedPair;}
return directPair;},_getQuoteDigits:function(symbol)
{try{digits=this._tools.getElementBy("symbol",symbol).digits;}catch(e){digits=6;}
return digits;},_getText:function(key,params)
{params=params||{};if(typeof Broco.TraderCalc.Languages[this._locale][key]!="undefined"){var text=""+Broco.TraderCalc.Languages[this._locale][key];for(var macro in params){text=text.replace(new RegExp("%"+macro+"%"),params[macro]);}
return text;}else{return key;}},_numberFormat:function(number,decimals,decPoint,thousandsSep)
{if(typeof number=="number"){number=number+"";}
decimals=decimals||0;decPoint=decPoint||".";if(typeof thousandsSep=="undefined"){thousandsSep=" ";}
var matches=number.match(/^(\-)?(\d+)(?:\.(\d+))?$/);if(typeof matches[2]=="undefined"){return number;}
number="";var sign=matches[1]||"";var integer=matches[2];var frac=matches[3]||"";number+=sign=="-"?"&minus;":"";for(i=0;i<integer.length;i++){number+=integer.substr(i,1);if((integer.length-i)%3==1&&i<integer.length-1){number+=thousandsSep;}}
if(decimals>0){number+=decPoint;for(i=0;i<decimals;i++){number+=i<frac.length?frac.substr(i,1):"0";}}
return number;},_fixInvalidNumber:function(number)
{if(typeof number=="string"){number=number.replace(/^(\d*),(\d+)/,'$1.$2');number=number.replace(/^(\.\d+)/,'0$1');}
return number;},_loadSpecificationsFromJsonData:function(data)
{this._tools.removeAll();for(i in data['tools']){this._tools.addElement(data['tools'][i]);}
this._groups.removeAll();for(i in data['groups']){this._groups.addElement(data['groups'][i]);}
this._categories.removeAll();for(i in data['categories']){this._categories.addElement(data['categories'][i]);}
this._accountTypes.removeAll();for(i in data['account_types']){this._accountTypes.addElement(data['account_types'][i]);}
this._onSpecificationsLoaded();},_loadQuotesFromJsonData:function(data)
{this._quotes.removeAll();for(i in data['quotes']){this._quotes.addElement(data['quotes'][i]);}
this._onQuotesLoaded();},_loadCalculateResultFromJsonData:function(data)
{var dataFields=['success','deposit_currency','profit','level','max_profit_loss','profit_points','point_price','pledge','margin','fee','clear_profit','equity'];for(var i=0;i<dataFields.length;i++){if(typeof data[dataFields[i]]=='undefined'){data[dataFields[i]]=null;}}
if(!data.success){alert(data.message);return;}
var result=jQuery('.broco-tradercalc-result',this.container);result.empty();var html="<h2>"+this._getText("Header_Result")+"<i class=\"pic tradercalc-result\"></i></h2>"+"<dl>"+"<dt class=\"broco-tradercalc-profit\">"+this._getText("ResultTitle_Profit")+":</dt>"+"<dd class=\"broco-tradercalc-profit\">"+this._numberFormat(Math.round(data["profit"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>";if(data.balance>0){html+="<dt class=\"broco-tradercalc-equity\">"+this._getText("ResultTitle_Equity")+":</dt>"+"<dd class=\"broco-tradercalc-equity\">"+this._numberFormat(Math.round(data["equity"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>";}
if(data.balance>0&&data["level"]!==null){html+="<dt class=\"broco-tradercalc-level\">"+this._getText("ResultTitle_Level")+":</dt>"+"<dd class=\"broco-tradercalc-level\">"+this._numberFormat(Math.max(0,Math.round(data["level"]*100)/100),2)+"%"+
(Math.round(data["level"]*100)/100<70?' ('+this._getText("Comment_LevelTooSmall")+')':'')+"</dd>";}
html+="<dt class=\"broco-tradercalc-profit-points\">"+this._getText("ResultTitle_ProfitPoints")+":</dt>"+"<dd class=\"broco-tradercalc-profit-points\">"+this._numberFormat(Math.round(data["profit_points"]*100)/100,0)+"</dd>"+"<dt class=\"broco-tradercalc-point-price\">"+this._getText("ResultTitle_PointPrice")+":</dt>"+"<dd class=\"broco-tradercalc-point-price\">"+this._numberFormat(Math.round(data["point_price"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>";if(data.balance>0){html+="<dt class=\"broco-tradercalc-stop-out\">"+this._getText("ResultTitle_StopOut")+":</dt>"+"<dd class=\"broco-tradercalc-stop-out\">"+this._numberFormat(Math.max(0,Math.round(data["max_profit_loss"]*100)/100),2)+" "+data["deposit_currency"]+
(data["max_profit_loss"]<=0?' ('+this._getText("Comment_BalanceTooSmall")+')':'')+"</dd>";}
html+="</dl>";jQuery(html).appendTo(result);var category=this._getFormFieldValue("category");if(category=="forex"){jQuery("<dt class=\"broco-tradercalc-pledge\">"+this._getText("ResultTitle_Pledge")+":</dt>"+"<dd class=\"broco-tradercalc-pledge\">"+this._numberFormat(Math.round(data["pledge"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>").appendTo(jQuery("dl",result));}else if(category=="futures"){jQuery("<dt class=\"broco-tradercalc-margin\">"+this._getText("ResultTitle_Margin")+":</dt>"+"<dd class=\"broco-tradercalc-margin\">"+this._numberFormat(Math.round(data["margin"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>"+"<dt class=\"broco-tradercalc-fee\">"+this._getText("ResultTitle_Fee")+":</dt>"+"<dd class=\"broco-tradercalc-fee\">"+this._numberFormat(Math.round(data["fee"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>").appendTo(jQuery("dl",result));}else if(category=="stocks"){jQuery("<dt class=\"broco-tradercalc-margin\">"+this._getText("ResultTitle_Margin")+":</dt>"+"<dd class=\"broco-tradercalc-margin\">"+this._numberFormat(Math.round(data["margin"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>"+"<dt class=\"broco-tradercalc-fee\">"+this._getText("ResultTitle_Fee")+":</dt>"+"<dd class=\"broco-tradercalc-fee\">"+this._numberFormat(Math.round(data["fee"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>"+"<dt class=\"broco-tradercalc-clear-profit\">"+this._getText("ResultTitle_ClearProfit")+":</dt>"+"<dd class=\"broco-tradercalc-clear-profit\">"+this._numberFormat(Math.round(data["clear_profit"]*100)/100,2)+" "+data["deposit_currency"]+"</dd>").appendTo(jQuery("dl",result));}},_onCalculateClick:function(e)
{this._requestResultAsJson();this._clearResults();},_onInputKeyPress:function(e)
{e=e||window.event;var code=(e.keyCode)?e.keyCode:e.which;if(code==13){this._requestResultAsJson();}},_onAccountTypeChange:function(e)
{this._updateCategorySelect();this._onCategoryChange(e);},_onCategoryChange:function(e)
{this._updateSymbolSelect();this._clearPrices();this._updatePrices();this._clearLots();this._updateConversionSymbols();this._updateExtendedFields();this._updateConversionRates();this._clearResults();},_onSymbolChange:function(e)
{this._clearPrices();this._updatePrices();this._updateConversionSymbols();this._updateExtendedFields();this._updateConversionRates();},_onDealTypeChange:function(e)
{this._clearPrices();this._updatePrices();},_onDepositCurrencyChange:function(e)
{this._updateConversionSymbols();this._updateExtendedFields();this._updateConversionRates();},_onSpecificationsLoaded:function()
{this._updateAccountTypeSelect();this._updateCategorySelect();this._updateSymbolSelect();this._updateExtendedFields();if(!this._toolsLoadedFirst){this._toolsLoadedFirst=true;if(this._quotesLoadedFirst){this._onSpecificationsAndQuotesLoadedFirst();}}},_onQuotesLoaded:function()
{if(!this._quotesLoadedFirst){this._quotesLoadedFirst=true;if(this._toolsLoadedFirst){this._onSpecificationsAndQuotesLoadedFirst();}}},_onSpecificationsAndQuotesLoadedFirst:function()
{this._updatePrices();this._updateConversionSymbols();this._updateExtendedFields();this._updateConversionRates();jQuery("input[type='button']",this.container).removeAttr('disabled');}});Broco.TraderCalc.Languages={}
Broco.TraderCalc.Languages.es_ES={'FieldTitle_AccountType':'Account type','FieldTitle_Category':'Categoría','FieldTitle_TradingTool':'Instrumento comercial','FieldTitle_DealType':'Tipo de la transacción','FieldTitle_Lots':'Volumen (lots)','FieldTitle_OpenPrice':'Precio de la apertura','FieldTitle_ClosePrice':'Precio del cierre','FieldTitle_Balance':'Balance','FieldTitle_DepositCurrency':'Divisa del depósito','FieldTitle_ToolConversionRate':'Cierre %symbol%','FieldHint_ToolConversionRate':'El curso para la transferencia de ganancias a la divisa del depósito','FieldTitle_MarginConversionRate':'Apertura  %symbol%','FieldHint_MarginConversionRate':'El curso para la transferencia del empeño a la divisa del depósito','FieldTitle_Expander':'Palanca','Button_Calculate':'Calcular','Header_Result':'Resultado','ResultTitle_Profit':'Ganancias','ResultTitle_Equity':'Equity','ResultTitle_Level':'Nivel','ResultTitle_ProfitPoints':'Ganancias en los puntos','ResultTitle_PointPrice':'Precio del punto','ResultTitle_StopOut':'La pérdida máxima','ResultTitle_Pledge':'Empeño','ResultTitle_Margin':'Margen','ResultTitle_Fee':'Comisión','ResultTitle_ClearProfit':'Beneficio líquido','Comment_BalanceTooSmall':'entered balance is too small for this operation','Comment_LevelTooSmall':'when level is less than 70% the position will be closed by stop-out'}
Broco.TraderCalc.Languages.ru_UA={'FieldTitle_AccountType':'Account type','FieldTitle_Category':'Категорія','FieldTitle_TradingTool':'Торговий інструмент','FieldTitle_DealType':'Тип операції','FieldTitle_Lots':'Об&#8217;єм (lots)','FieldTitle_OpenPrice':'Ціна відкриття','FieldTitle_ClosePrice':'Ціна закриття','FieldTitle_Balance':'Баланс','FieldTitle_DepositCurrency':'Валюта депозиту','FieldTitle_ToolConversionRate':'Закриття %symbol%','FieldHint_ToolConversionRate':'Курс для перерахунку прибутку у валюту депозиту','FieldTitle_MarginConversionRate':'Відкриття %symbol%','FieldHint_MarginConversionRate':'Курс для перерахунку застави у валюту депозиту','FieldTitle_Expander':'Плече','Button_Calculate':'Порахувати','Header_Result':'Результат','ResultTitle_Profit':'Прибуток','ResultTitle_Equity':'Средства','ResultTitle_Level':'Рівень','ResultTitle_ProfitPoints':'Прибуток в пунктах','ResultTitle_PointPrice':'Ціна пункту','ResultTitle_StopOut':'Макс. убиток','ResultTitle_Pledge':'Застава','ResultTitle_Margin':'Маржа','ResultTitle_Fee':'Комісія','ResultTitle_ClearProfit':'Чистий прибуток','Comment_BalanceTooSmall':'введенный баланс слишком мал для данной операции','Comment_LevelTooSmall':'при уровне меньше 70% – сделка закроется по стоп-ауту'}
Broco.TraderCalc.Languages.en_US={'FieldTitle_AccountType':'Account type','FieldTitle_Category':'Category','FieldTitle_TradingTool':'Trading tool','FieldTitle_DealType':'Deal type','FieldTitle_Lots':'Lots','FieldTitle_OpenPrice':'Open price','FieldTitle_ClosePrice':'Close price','FieldTitle_Balance':'Balance','FieldTitle_DepositCurrency':'Deposit currency','FieldTitle_ToolConversionRate':'Closing of %symbol%','FieldHint_ToolConversionRate':'Profit to deposit currency conversion rate','FieldTitle_MarginConversionRate':'Opening of %symbol%','FieldHint_MarginConversionRate':'Pledge to deposit currency conversion rate','FieldTitle_Expander':'Expander','Button_Calculate':'Calculate','Header_Result':'Result','ResultTitle_Profit':'Profit','ResultTitle_Equity':'Equity','ResultTitle_Level':'Level','ResultTitle_ProfitPoints':'Profit points','ResultTitle_PointPrice':'Point price','ResultTitle_StopOut':'Stop-out','ResultTitle_Pledge':'Pledge','ResultTitle_Margin':'Margin','ResultTitle_Fee':'Fee','ResultTitle_ClearProfit':'Clear profit','Comment_BalanceTooSmall':'entered balance is too small for this operation','Comment_LevelTooSmall':'when level is less than 70% the position will be closed by stop-out'}
Broco.TraderCalc.Languages.zh_ZH={'FieldTitle_AccountType':'Account type','FieldTitle_Category':'种类','FieldTitle_TradingTool':'交易工具','FieldTitle_DealType':'交易种类','FieldTitle_Lots':'量(手)','FieldTitle_OpenPrice':'开盘','FieldTitle_ClosePrice':'收盘价格','FieldTitle_Balance':'帐户余款','FieldTitle_DepositCurrency':'存款货币','FieldTitle_ToolConversionRate':'收盘 %symbol%','FieldHint_ToolConversionRate':'把利润变换为存款货币率','FieldTitle_MarginConversionRate':'开通%symbol%','FieldHint_MarginConversionRate':'把保证把利润变换为存款货币率','FieldTitle_Expander':'杠杆','Button_Calculate':'结算','Header_Result':'结果','ResultTitle_Profit':'利润','ResultTitle_Equity':'Equity','ResultTitle_Level':'水平','ResultTitle_ProfitPoints':'以点利润','ResultTitle_PointPrice':'点价格','ResultTitle_StopOut':'最大的损失','ResultTitle_Pledge':'保证','ResultTitle_Margin':'保证金','ResultTitle_Fee':'佣金','ResultTitle_ClearProfit':'净利','Comment_BalanceTooSmall':'entered balance is too small for this operation','Comment_LevelTooSmall':'when level is less than 70% the position will be closed by stop-out'}
Broco.TraderCalc.Languages.ru_RU={'FieldTitle_AccountType':'Тип торгового счета','FieldTitle_Category':'Категория','FieldTitle_TradingTool':'Торговый инструмент','FieldTitle_DealType':'Тип сделки','FieldTitle_Lots':'Объем (lots)','FieldTitle_OpenPrice':'Цена открытия','FieldTitle_ClosePrice':'Цена закрытия','FieldTitle_Balance':'Баланс','FieldTitle_DepositCurrency':'Валюта депозита','FieldTitle_ToolConversionRate':'Закрытие %symbol%','FieldHint_ToolConversionRate':'Курс для перевода прибыли в валюту депозита','FieldTitle_MarginConversionRate':'Открытие %symbol%','FieldHint_MarginConversionRate':'Курс для перевода залога в валюту депозита','FieldTitle_Expander':'Плечо','Button_Calculate':'Посчитать','Header_Result':'Результат','ResultTitle_Profit':'Прибыль','ResultTitle_Equity':'Средства','ResultTitle_Level':'Уровень','ResultTitle_ProfitPoints':'Прибыль в пунктах','ResultTitle_PointPrice':'Цена пункта','ResultTitle_StopOut':'Макс. убыток','ResultTitle_Pledge':'Залог','ResultTitle_Margin':'Маржа','ResultTitle_Fee':'Комиссия','ResultTitle_ClearProfit':'Чистая прибыль','Comment_BalanceTooSmall':'введенный баланс слишком мал для данной операции','Comment_LevelTooSmall':'при уровне меньше 70% – сделка закроется по стоп-ауту'}
Broco.TraderCalc.Languages.ar_SA={'FieldTitle_AccountType':'نوع الحساب','FieldTitle_Category':'الفئة','FieldTitle_TradingTool':'أداة التسوق','FieldTitle_DealType':'النوع العملية ','FieldTitle_Lots':' الحجم (lots)','FieldTitle_OpenPrice':'سعر الافتتاح','FieldTitle_ClosePrice':'سعر الاغلاق','FieldTitle_Balance':'التوازن','FieldTitle_DepositCurrency':'عملة الايداع','FieldTitle_ToolConversionRate':' اغلاق %symbol%','FieldHint_ToolConversionRate':'تحويل الربح الى سعر صرف عملة الايداع','FieldTitle_MarginConversionRate':'فتح  %symbol%','FieldHint_MarginConversionRate':'تحويل الهامش الى سعر صرف عملة الايداع','FieldTitle_Expander':'دعم الرصيد','Button_Calculate':'حساب','Header_Result':'النتيجة','ResultTitle_Profit':'الربح','ResultTitle_Equity':'الرصيد','ResultTitle_Level':'نسبة استخدام الهامش','ResultTitle_ProfitPoints':'نقاط الربح','ResultTitle_PointPrice':'سعر النقطة','ResultTitle_StopOut':'أيقاف حساب','ResultTitle_Pledge':'الهامش','ResultTitle_Margin':'الهامش','ResultTitle_Fee':'الرسم','ResultTitle_ClearProfit':'الربح الصافي','Comment_BalanceTooSmall':'الرصيد الكلي المدخل غير كافي لهذه العملية','Comment_LevelTooSmall':'عندما تصل نسبة استعمال الهامش الى أقل من 70% سوف يتم اغلاق المركز بايقاف الحساب'}
Broco.TraderCalc.DefaultConfig={specificationsUri:'http://service.brocompany.com/trader-calc/specifications-list/format/jsonp',quotesUri:'http://service.brocompany.com/trader-calc/quotes-list/format/jsonp',calculateUri:'http://service.brocompany.com/trader-calc/calculate/format/jsonp',updateSpecificationsInterval:1800000,updateQuotesInterval:120000,jsonp:true}