package jforex.guitests;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Param {
    String value();
}

/**
 * The strategy demonstrates how one can create his own parameter dialog.
 * Launch the strategy, change the parameters and check the console that they have been successfully changed.
 * Note to input proper values according to parameter type
 *
 */
public class MyParamStrategy implements IStrategy {

    @Param("boolean param description")
    public boolean booleanParam = true;
    @Param("double param description")
    public double doubleParam = 5.0;
    @Param("int param description")
    public int intParam = 5;
    @Param("string param description")
    public String stringParam = "some string";

    private IConsole console;

    public void onStart(IContext context) throws JFException {

        this.console = context.getConsole();
        printFields("Parameters before:");
        try {
            SwingUtilities.invokeAndWait(new Runnable() {

                @Override
                public void run() {
                    new ParamDialog(MyParamStrategy.this);
                }
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        printFields("Parameters after:");
    }
    
    private void printFields(String comment){
        console.getOut().println(comment);
        Field[] fields = this.getClass().getFields();
        for (Field field : fields) {
            Param parameter = field.getAnnotation(Param.class);
            if (parameter != null) {
                try {
                    console.getOut().println(String.format("Parameter %s=%s",parameter.value(), field.get(this)));
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void onTick(Instrument instrument, ITick tick) throws JFException {    }

    public void onStop() throws JFException {}

    public void onAccount(IAccount account) throws JFException {
    }

    public void onMessage(IMessage message) throws JFException {
    }

    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
    }
}

@SuppressWarnings("serial")
class ParamDialog extends JDialog {

    private final IStrategy strategy;
    private final Map<Field,JTextField> fieldMap = new  HashMap<Field,JTextField>();

    public ParamDialog(IStrategy strategy) {
        this.strategy = strategy;
        this.setModal(true);
        
        Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
        int width = 150;
        int height = 150;
        
        int x = (screen.width - width) / 2;
        int y = (screen.height - height) / 2;
        setBounds(x, y, width, height);
        

        addComponentsToPane(this.getContentPane());
        pack();
        
        setVisible(true);
    }

    public void addComponentsToPane(Container pane) {
        pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));

        Field[] fields = strategy.getClass().getFields();
        for (Field field : fields) {
            Param parameter = field.getAnnotation(Param.class);
            if (parameter != null) {
                JPanel paramPanel = new JPanel();
                paramPanel.setLayout(new BoxLayout(paramPanel, BoxLayout.X_AXIS));
                paramPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
                JLabel label = new JLabel(parameter.value());
                label.setPreferredSize(new Dimension(200, 20));
                paramPanel.add(label, BorderLayout.WEST);
                try {
                    JTextField textField = new JTextField(String.valueOf(field.get(strategy)));
                    textField.setHorizontalAlignment(JTextField.RIGHT);
                    textField.setPreferredSize(new Dimension(100, 20));
                    paramPanel.add(textField, BorderLayout.EAST);
                    fieldMap.put(field, textField);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                pane.add(paramPanel);
            }
        }
        JButton button = new JButton("OK");
        button.setAlignmentX(Component.CENTER_ALIGNMENT);
        button.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                for(Map.Entry<Field, JTextField> entry : fieldMap.entrySet()){
                    try {
                        Field field = entry.getKey();
                        String stringValue = entry.getValue().getText();
                        if( field.getType() == double.class){
                            field.set(strategy,Double.valueOf(stringValue));
                        } else if( field.getType() == int.class){
                            field.set(strategy,Integer.valueOf(stringValue));
                        } else if( field.getType() == boolean.class){
                            field.set(strategy,Boolean.valueOf(stringValue));
                        } else if( field.getType() == String.class){
                            field.set(strategy,stringValue);
                        }
                        
                        
                    } catch (IllegalArgumentException e1) {
                        e1.printStackTrace();
                    } catch (IllegalAccessException e1) {
                        e1.printStackTrace();
                    }
                }
                ParamDialog.this.setVisible(false);
                ParamDialog.this.dispose();
            }});
        pane.add(button);
    }

}