//package jforex;

import java.io.*;
import java.util.*;

import com.dukascopy.api.*;
import com.dukascopy.api.feed.IFeedDescriptor;
import com.dukascopy.api.feed.util.TicksFeedDescriptor;
import com.dukascopy.api.indicators.*;


public class CheckChartAddInd implements IStrategy {
	@SuppressWarnings( "unused"  )
	private IEngine engine;
	private IConsole console;
	@SuppressWarnings( "unused"  )
	private IHistory history;
	private IContext context;
//	@SuppressWarnings( "unused"  )
	private IIndicators indicators;
	//private IUserInterface userInterface;
	private PrintStream out;
//	@SuppressWarnings( "unused"  )
	private PrintStream err;
	@SuppressWarnings( "unused"  )
	private IUserInterface gui;
	//
	//
	private Instrument instr = Instrument.EURGBP;
	
	private IChart chart;
	
	Set<Instrument> instruments = new HashSet<Instrument>();
	
	
	
	@Override
	public void onStart( IContext context ) throws JFException {
		this.engine = context.getEngine();
		this.console = context.getConsole();
		this.history = context.getHistory();
		this.context = context;
		this.indicators = context.getIndicators();
		this.out = console.getOut();
		this.err = console.getErr();
		
		out.println( "STARTING..." );
		//
		instruments.add( instr );
		//
	//	out.format( "...instruments.size: %d %n", instruments.size() );
		//
		context.setSubscribedInstruments( instruments, true );		
		//
	//	out.format( "...instruments.size: %d %n", instruments.size() );
		//
		String IndName = "";
		//
		IndName = indicators.registerCustomIndicator( IndicatorRMICCCC.class );
		//
		out.format( "Indicator Name: %s %n", IndName );
		//
		out.println( "STARTING...DONE" );
		
	}
	
	
	@Override
	public void onStop() throws JFException {
		out.println( "STOPPING..." );
	}

	@Override
	public void onAccount( IAccount account ) throws JFException {
	}

	@Override
	public void onMessage( IMessage message ) throws JFException {
	}

	@Override
	public void onTick( Instrument instrument, ITick tick ) throws JFException {
		//
	}
		
	@Override
    public void onBar( Instrument instrument, Period period, IBar askBar, IBar bidBar ) throws JFException {
    	//
		if ( !instrument.equals( instr ) ) return;
		//
	//	out.format( "... %s: onBar %n", instrument.toString() );
		//
		if ( period.equals( Period.ONE_MIN ) ) {
			try {
				onBar_addInd( instrument );
			}
			catch ( Exception exc ) {
				exc.printStackTrace( err );
			}
		}
		
    }
    
	private void onBar_addInd( Instrument instrument ) throws JFException {
		//
		out.format( "... %s: onBar_addInd %n", instrument.toString() );
		//
		if ( chart == null ) {
			chart = context.getChart( instrument );
		}
		//
		if ( chart == null ) {
			//
			out.format( "... %s: chart NOT exist!! %n", instrument.toString() );
			//
			IFeedDescriptor feedDsc = new TicksFeedDescriptor( instrument );
			//
			feedDsc.setDataType( DataType.TIME_PERIOD_AGGREGATION );
			feedDsc.setPeriod( Period.ONE_MIN );
			feedDsc.setOfferSide( OfferSide.ASK );
			//
			chart = context.openChart( feedDsc );
			//
		}
		else {
			out.format( "... %s: chart exists!! %n", instrument.toString() );
		}
		//
		if ( chart.getIndicators() != null && chart.getIndicators().size() == 0 ) {
			
			out.format( "... %s: indicator NOT exist!! %n", instrument.toString() );
			
/*			
	 		//This is OK:
			IChartPanel rmiPanel = chart.add( indicators.getIndicator("RMI"), new Object[]{15, 1});
*/			
			
			//This is PROBLEM:
			//
			IndicatorRMICCCC indRMIC = new IndicatorRMICCCC();
			//
			//indRMIC.
			//
			@SuppressWarnings( "unused" )
		    IChartPanel rmiPanel = chart.add( indRMIC, new Object[]{15, 1});
			
		}
		else {
			out.format( "... %s: indicator exists!! %n", instrument.toString() );
		}
		
		
		
/*
*/		
		
		
		
	}
	
	
}


//=====================================================================================================

/*
 * Copyright 2011 Dukascopy® (Suisse) SA. All rights reserved.
 * DUKASCOPY PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */

/**
 * 
 * @author anatoly.pokusayev
 *
 */

class IndicatorRMICCCC implements IIndicator {
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private double[][] inputs = new double[1][];
    private double[][] outputs = new double[1][];    
    private int timePeriod = 14;
    private int momentumPeriod = 1;
        
    public void onStart(IIndicatorContext context) {    	
        indicatorInfo = new IndicatorInfo("RMICCCC", "Relative Momentum Index Custom", "My indicators", false, false, true, 1, 2, 1);
        inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Price", InputParameterInfo.Type.DOUBLE)};
        optInputParameterInfos = new OptInputParameterInfo[] {
        		new OptInputParameterInfo("Time period", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(14, 2, 2000, 1)),
        		new OptInputParameterInfo("MomentumPeriod", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(momentumPeriod, 1, 500, 1))};
        outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("out", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE)};        
    }
    
    public IndicatorResult calculate(int startIndex, int endIndex) {        
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
        if (startIndex >= endIndex) {
            return new IndicatorResult(0, 0);
        }
        
        int i, outIdx = 0, today = startIndex - getLookback() + momentumPeriod, prev = today - momentumPeriod;                        
        double prevValue = inputs[0][prev], prevGain = 0, prevLoss = 0, tempValue1, tempValue2;        
        
        for (i = timePeriod; i > 0; i--) {
        	tempValue1 = inputs[0][today++];
        	tempValue2 = tempValue1 - prevValue;
        	prevValue  = inputs[0][++prev];
            if( tempValue2 < 0 ) prevLoss -= tempValue2;
            else prevGain += tempValue2;             
        }
        prevGain /= timePeriod;
        prevLoss /= timePeriod;            
        
        if( today > startIndex){
        	tempValue1 = prevGain + prevLoss;
            outputs[0][outIdx++] = tempValue1 == 0 ? 0 : 100 * (prevGain / tempValue1);
        }
        while (today <= endIndex) {       	        	
        	tempValue1 = inputs[0][today++];
            tempValue2 = tempValue1 - prevValue;
            prevValue  = inputs[0][++prev];

            prevLoss *= (timePeriod-1);
            prevGain *= (timePeriod-1);
            
      	  	if( tempValue2 < 0 ) prevLoss -= tempValue2;
            else prevGain += tempValue2;

            prevLoss /= timePeriod;
            prevGain /= timePeriod;
            tempValue1 = prevLoss + prevGain;
            outputs[0][outIdx++] = tempValue1 == 0 ? 0 : 100 * (prevGain / tempValue1);        	
       }
       return new IndicatorResult(startIndex, outIdx);
    }

    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;     
    }

    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }
    
    public int getLookback() {
        return  momentumPeriod + timePeriod;        
    }

    public int getLookforward() {
        return 0;
    }

    public OptInputParameterInfo getOptInputParameterInfo(int index) {
        if (index <= optInputParameterInfos.length) {
            return optInputParameterInfos[index];
        }
        return null;
    }

    public OutputParameterInfo getOutputParameterInfo(int index) {
        if (index <= outputParameterInfos.length) {
            return outputParameterInfos[index];
        }
        return null;
    }

    public void setInputParameter(int index, Object array) {
        inputs[index] = (double[]) array;
    }

    public void setOptInputParameter(int index, Object value) {
    	switch (index) {	        	
        case 0:
            timePeriod = (Integer) value;   	                            	               
            break;
        case 1:
            momentumPeriod = (Integer) value;	                            	                
            break;                    	          
        default:
            throw new ArrayIndexOutOfBoundsException(index);
    	}        
    }

    public void setOutputParameter(int index, Object array) {
        outputs[index] = (double[]) array;
    }   
}
