/**
 *  @param int id
 *  @param array init
 *  @param bool or array  loadRelated
 *  @param string step
 *  @callbacks object after stepChanged
 */
function PositionPlatform(id, init, loadRelated, step, stepChangeCallbacks, generalCallbacks){	
	//public properties
	this.errors = false;
	/**
	 * countdown object, needed mainly for 
	 * "cancel" feature
	 */
	
	this.countdown = new Countdown();
	
	/**
	 *  
	 */
	this.buyMeOutCountdown = new Countdown();
	this.buyMeOutStatus = null;
	this.buyMeOutRate   = null;
	this.buyMeOutPrice  = null;
	this.buyMeOutPayoutId = null; //needed for validation of payout rate
	
	
	this.rolloverPosible = true;
	
	this.sellPosible = true;

	/* 
	 * This flag set to true when 
	 * option end date is not schedules for today
	 */
	this.isFuture = false;
	/*
	 *  current state of the position - win/lose/tie
	 * */
	this.state = false;
	//private properties
	var _fields = ['id', 'position', 'customerId', 'rate', 
	              'originalRate', 'optionId', 'payout', 
	              'amount', 'currency', 'status', 'date', 
                  'dateMS', 'leveratePositionId'];
	//those field are in MYSQL TIMESTAMP formats
	var _timeFields = new Array('date');
	
	var _loadRelated = loadRelated;
	
	var _stepChangeCallbacks = stepChangeCallbacks;
	
	var _generalCallbacks = generalCallbacks;
	
	var _step = null;
	//as long is this property set to true
	//the position can be canceled
	var _cancelEnabled = true;
	
	var _relatedClasses = {
		optionId:   'Option',
		customerId: 'Customer'
	};
	/* set the percentage to the new position using roll over function - need to move to site options */
	var  _rollOverPercentage = 30; 
    
    var _serverErrorsMap = {notLoggedIn:             AppData.langHome.loginPopupTitle, 
                            optionIsClosed:          AppData.langHome.optionIsClosedErrorPopupMessage,
                            insufficientFunds:       AppData.langHome.insufficientFundsIsErrorPopupMessage,
                            invalidPositionRate:     AppData.langHome.positionRateIsInvalid,
                            suspended:               AppData.langHome.optionSuspendedPopupMessage,
                            riskSuspentionActivated: AppData.langHome.riskSuspentionPopupMessage}
	
	var _that = this;
	
	//public methods
	this.setStep = function(step){
		var availableSteps = ['new', 'valid', 'notValid', 'saved', 'canceled', 'open', 'expired'];
		var ansInArray = $.inArray(step, availableSteps);
		if(typeof ansInArray != 'undefined' && ansInArray != -1){
			_step = step;
			if(typeof _stepChangeCallbacks[_step] == 'function'){
				 stepChangeCallbacks[_step](_that.id);
			}
		}
		else{
			alert('Unavailable step status');
			return false;
		}
	}
	
	this.getStep = function(){return _step}
	/**
	 * make position e.g write to db
	 * 
	 */
	this.make = function(){
		if(!_that.errors){
			//re-inshure that position is valid
			AjxMgr.request('rpcProxy/newPosition' , 'POST', {amount: _that.amount, 
							position: _that.position, assetId: _that.optionId.assetId.id, 
							optionId: _that.optionId.id, sourcePlatform: 'floating'}, 'json', true, serverReply);
		}
		else{
			_that.setStep('notValid')
		}	
		function serverReply(data){
			if(typeof data == 'string'){//error occured when position was checked on server side
				validationFailed([_serverErrorsMap[data]]);
			}
			else{
				_that.isFuture = determineIsFuture();
				
				_that.errors = false;
				_that.date = data.date;
				_that.dateMS = data.positionDate * 1000;
				_that.payout = data.positionPayout;
				_that.id 	= data.positionId;
                _that.leveratePositionId = data.leveratePositionId;
				_that.rate 	= data.positionRate;
				_that.status = 'open';
				_that.setStep('saved');
			}
		}
	}
	
	this.cancel = function(){
		function serverReply(data){
			_cancelEnabled = false;
			_that.setStep('canceled');
		}
		if(_cancelEnabled){
			_that.countdown.destruct();
			AjxMgr.request('rpcProxy/changePositionStatus/canceled/' + _that.id + '/true' , 'POST', {}, 'json', true, serverReply);
		}
	}
	
	this.cancelCountdownEnded = function(){
		_that.countdown.destruct();
		_that.setStep('open');
		_that.initLS();
	}
	//initilization of LS, needed for recieving current rate
	this.initLS = function(){
		 var assetId = _that.optionId.assetId.id;
		 var optionId = _that.optionId.id
		 //subscribe only if assetId and optionId is defined
		 if(typeof assetId != 'undefined' && typeof optionId != 'undefined'){
		 
			if (AppData.streamer != "spot")
				var page = General.initLightstreamer();

			if (AppData.streamer == "spot")
				var itemName  ='assetPlatform_' + assetId + '_' + optionId + '_' + AppData.whiteLabelName;
			else
				var itemName = (flowPage.getPlatformMode() == 'regular') 
					? 'assetPlatform_' + assetId + '_' + optionId + '_' + AppData.whiteLabelName 
					: 'feed_assetPlatform_' + assetId + '_' + optionId + '_' + AppData.whiteLabelName;

			 var positionToSubscribe = [];
			 positionToSubscribe.push (itemName);
			 //page.removeTable('assetsTablePlatform');

			if (AppData.streamer == "spot") {
				Streamer.subscribe(positionToSubscribe, _that.onRateUpdate);
			} else {
				var assetsTable   = new NonVisualTable(positionToSubscribe, ['rate', 'id', 'lastUpdated', 'color', 'pricingRate'], "MERGE");
				page.addTable(assetsTable, 'assetsPositionsPlatform' + _that.id);
				assetsTable.onItemUpdate =  _that.onRateUpdate;
			}
		 }
	}
	
	this.onRateUpdate = function(item, itemUpdate, itemName){
		if (AppData.streamer == "spot") {
			var data = itemUpdate;
			itemName = item;

			var pricingRate = data.pricingRate;
			var color = data.color;
			var lastUpdated = data.lastUpdated;
		} else {
			var pricingRate = itemUpdate.getNewValue('pricingRate');
			var color = parseInt(itemUpdate.getNewValue('color'));
			var lastUpdated = itemUpdate.getNewValue('lastUpdated');
		}
		 
		  //update current rate		 
		  _that.calculateCurrentPayout(pricingRate);
		  _generalCallbacks['rateChanged'](_that.id, pricingRate, _that);
	}
	
	this.calculateCurrentPayout = function(currentRate){
		/* update payout color and element background color (class) in open positions */
		var currentPayout = 0;
		
		if((_that.position == 'call' && parseFloat(currentRate) > parseFloat(_that.rate)) ||
			(_that.position == 'put' && parseFloat(currentRate) < parseFloat(_that.rate))){ //positon winning
			currentPayout = (100 + parseInt(_that.optionId.profit)) * parseInt(_that.amount)/100;
			//when winning, rollover not possible
			_that.rolloverPosible = false;
			_that.state = 'win';
		}
		
		if((_that.position == 'call' && parseFloat(currentRate) < parseFloat(_that.rate)) || 
			(_that.position == 'put' && parseFloat(currentRate) > parseFloat(_that.rate))){ //positon losing
			currentPayout = (100-parseInt(_that.optionId.loss)) * parseInt(_that.amount)/100;
			//when loosing rollover possible
			_that.rolloverPosible = true;
			_that.state = 'lose';
		}
		
		if( parseFloat(currentRate) == parseFloat(_that.rate)){//no change
			currentPayout = parseInt(_that.amount);
			_that.rolloverPosible = false;
			_that.state = 'tie';
		}
		//callback
		 _generalCallbacks['payoutCalculated'](_that.id, currentPayout);
	}
	//
	this.rollover = function(newOption, callback){
		var newAmount = parseFloat(_that.amount * (_rollOverPercentage/100) + parseInt(_that.amount)).toFixed(2);
		
		var rolloverCompleted = function(data){
			if(data['status'] == "true"){
				_that.amount   		= newAmount;
				_that.optionId 		= newOption;
				_that.optionEndDate = newOption.endDate;
				_that.date = data.date;
				_that.dateMS = data.positionDate * 1000;
				_that.initLS();
			}
			callback(data);
		}
		 
		
		
		$.post('rpcProxy/rollover', {
                   positionId: _that.id,
                   optionId  : newOption.id,
                   assetId   : _that.optionId.assetId.id,
                   newAmount :  newAmount,
                   percentage: _rollOverPercentage
                  }, rolloverCompleted, 'json');
		  
	}
	/*
	 *  gets current buy my out price from the server
	 */
	this.getBuyMeOutPrice = function(callback){
		
		/*
		 * data = {status , payout, expiryRate- by this rate the payuot was calculated}
		 */
		var serverReply = function(data){
			
			_that.buyMeOutStatus = (data['status'] == "true") ? true : false;
			_that.buyMeOutRate 	 = (typeof data['expiryRate'] != 'undefined') ? data['expiryRate'] : false;
			_that.buyMeOutPrice  = (typeof data['payout'] != 'undefined') ? data['payout'] : false;
			_that.buyMeOutPayoutId = data['payoutId'];
			
			if(!_that.buyMeOutStatus)//error occured
				_that.errors = AppData.bmoErrors[data['status']];
			
			if(typeof callback == 'function'){
				
				callback();
			}
		}
		
		AjxMgr.request('rpcProxy/getAndRecordBMOPayout' , 'POST', {
			entryRateParam: _that.rate,
			directionParam: _that.position,
			amountParam: _that.amount,
			assetIdParam: _that.optionId.assetId.id,
			currentOptionEndTimeParam: (_that.optionId.endDateMS - General.serverOffset)/1000,
			winParam: _that.optionId.profit,
			lossParam: _that.optionId.loss,
			positionIdParam: _that.id
		}, 'json', false, serverReply);
		
		
		
		
		
		//var data = {'status': 'true', 'payout': 100 };
		//serverReply(data);
	}
	
	this.buyMeOut = function(callback){
		var serverReply = function(data){
			_that.buyMeOutStatus = (data['status'] == "true") ? true : false;
			
			if(!_that.buyMeOutStatus)//error occured
				_that.errors = data['status']
			
			if(typeof callback == 'function'){
				callback();
			}
		}
		
		AjxMgr.request('rpcProxy/buyMeOut' , 'POST', {
			
			amountParam: _that.amount,
			assetIdParam: _that.optionId.assetId.id,
			positionIdParam: _that.id,
			optionIdParam: _that.optionId.id,
			payoutParam: _that.buyMeOutPrice,//this is buyMeOut price 
			expiryRateParam: _that.buyMeOutRate,// rate 
			payoutIdParam: _that.buyMeOutPayoutId//needed for buy me out validation
		}, 'json', true, serverReply);
		
		
	}
	
	//private methods
	var retrieveData = function(data){
		$.each(data, function(name, value){
			_that[name] = value;
			var ansInArray = $.inArray(name, _timeFields);
			if(typeof ansInArray != 'undefined' && ansInArray != -1){//convert time string to ms(in correct time zone
				_that[name + 'MS'] = iOkun.strtotime(value) * 1000 +  General.browserOffset;
			}
		});
		if(typeof _loadRelated == 'object'){
			//in this case loadRelated contains object of related classes
			$.each(_loadRelated, function(idRelated, relatedObject){
				_that[idRelated] = relatedObject;
			});
			loadRelated = true;
		}
		else if(typeof _loadRelated == 'boolean' && _loadRelated === true){
			$.each(_relatedClasses, function(idRelated, className){
				//load related objects
				if(className == 'Option'){
					_that[idRelated] = new window[className](_that[idRelated], false, true, 'platform', 'open');
				}
				else{
					_that[idRelated] = new window[className](_that[idRelated], false, true);
				}
			});
		}
		//create missing properties
		if(_step == 'new'){
			for(var i in _fields){
				if(!_that[_fields[i]]){					
					_that[_fields[i]] = null;
				}
			}
		}
	}
	/**
	 * called when validation of the form completed,
	 * the method updates validated properties of the object, and set position step to "valid"
	 */
	var validationCompleted = function(form){
		console.log('validation competed')
		_that.errors = false;
		_that.position = $(form).find('input[name="position"]').val();
		_that.amount   = $(form).find('input[name="amount"]').val();
		_that.setStep('valid');
		
	}
	
	var validationFailed = function(errors){
		_that.errors = errors;
        /* enable form submition */
        toggleFormSubmitionStatus(false);
		_that.setStep('notValid');
	}
	
	var determineIsFuture = function(){
		 var optionEndDateParts = iOkun.fetchPartsFromTimestampString(_that.optionId.endDate);
		 var currenDateParts = iOkun.convertUnixTime(General.dateTime.getTime());
		 //determine if current position made fopr future option
		 if(optionEndDateParts['month'] != currenDateParts['month'] || optionEndDateParts['day'] != currenDateParts['day']){
			 return true;
		 }
		 
		 return false;
	}
    
    var toggleFormSubmitionStatus = function(disable){
         $('form#platformForm').find('input[type="submit"]')
						.attr('disabled', disable);
    }
	
	//constructor
	this.setStep(step);
	retrieveData(init);
	
	_that.isFuture = determineIsFuture();
	
	if(_step == 'new'){
        
		//initiliaze form validaton function
		
		/**
		 * becase we can't override initialization of jQuery validation
		 * plugin, we need to create new form from hidden template every time 
		 * when new position object created
		 */
		if($('form#platformForm').size()){
			
            $('form#platformForm').remove();
		}
		
		var form = $('form#platformFormTemplate').clone(true);
		
        $('#platformAction').append(form.attr('id', 'platformForm').removeClass('hidden'));
		form.find('div.platformCountdownContainer').attr('id', 'platformCountdownContainer')
			.end()
			.find('input.platformApprove').attr('id', 'platformApprove')
			.end()
			.find('input.platformCancel').attr('id', 'platformCancel')
		
		
		//init validation plugin
		$('form#platformForm').validate({
			rules: {
				amount: {
					required: true,
					number: true,
					min: this.optionId.minPosition,
					max: this.optionId.maxPosition
				},
				position: {
					required: true
				}
			},
			messages: {
				amount: {
					required: langErrors.amountRequired,
					min: langErrors.minAmount,
					max: langErrors.maxAmount,
					number: langErrors.amountNotNumber
				},
				position: {
					required: langErrors.directionRequired
				}
				
			},
			onfocusout: false,
			onkeyup: false,
			showErrors: function(errorMap, errorList){
				var errorsArray = [];
				$.each(errorMap, function(fieldName, errorMessage){
					errorsArray.push(errorMessage);
				});
				
				if(errorsArray.length)
					validationFailed(errorsArray);
			},
			submitHandler: function(form){
				//preventing multiple positions
                toggleFormSubmitionStatus(true);
               
				validationCompleted(form);
			}
		});
	}
	//if this is open positions,
	//initilize LS for rate updates
	if(_step == 'open'){
		_that.initLS();
	}
	
	//if(!(init)) AjxMgr.request(AjxMgr.pathAjax + 'getOptions' , 'POST', {ids: id}, 'json', false, retrieveData);
	//else retrieveData(init);
}

//static properties
PositionPlatform.createOpenPositionsList = function(openPositions){
	var html = '';
	$.each(openPositions, function(i, openPosition){
		html += '<ul id="platformPosition_' + openPosition.id + '" optionid="' + openPosition.optionId.id + '">';
		html += PositionPlatform.createOpenPositionRecord(openPosition, false);
		html += '</ul>';
	});
		
	return html;
}

PositionPlatform.createOpenPositionRecord = function(openPosition, wrapWithUl){
	
	var html = '';
    if (flowPage.getPlatformMode() == 'regular')
            html += '<li>' + openPosition.id + '</li>';
        else if (flowPage.getPlatformMode() == 'floating')
            html += '<li>' + openPosition.leveratePositionId + '</li>';
        
	html += '<li>' + openPosition.assetName + '</li>';
	html += '<li>' + openPosition.date.split(' ')[1] + '</li>';
	html += '<li>' + openPosition.optionEndDate.split(' ')[1] + '</li>';
	html += '<li>' + openPosition.position + '<img alt="Call" src="appProxy/platform/' + openPosition.position +  'Sign.png" /></li>';
	html += '<li>' + openPosition.rate + '</li>';
	html += '<li class="platformPositionRate"></li>';
	html += '<li class="platformInvestment">' + openPosition.amount +  AppData.accountCurrency + '</li>';
	html += '<li class="platformCurrentPayout"></li>';
	if(openPosition.isFuture){
        html += '<li>' + langMain.futurePosition + '</li>';   
	}
	else{
		html += '<li><input type="button" value="" class="platformRollover" positionid="' + openPosition.id + '">';
		html += '<input type="button" value="" class="platformDoubleUp" positionid="' + openPosition.id + '"/>';
		//show sell button only where buyMeOut enabled for specific asset
		if(openPosition.optionId.assetId.bmoEnabled)
			html += '<input type="button" value="' + langMain.sell + '" class="platformSell" positionid="' + openPosition.id + '"/>';
		html += '</li>';
	}

	
	if(wrapWithUl){
		html = '<ul id="platformPosition_' + openPosition.id + '" optionid="' + openPosition.optionId.id + '">' + html + '</ul>';
	}
	//when ne position is made
	//sellPosible attribute of the option should be resseted to null
	//in order to enabl/disble sell btn
	openPosition.optionId.sellPosible = null;
	
	return html;
}
