/*
 * Created on 09.09.2004
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package TUGLaby;

import java.awt.Color;
import java.awt.datatransfer.DataFlavor;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.LinkedList;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;

import PrintGame.Action;
import PrintGame.Condition;
import PrintGame.Instruction;

/**
 * @author auguan@sbox
 * 
 * TODO To change the template for this generated type comment go to Window -
 * Preferences - Java - Code Style - Code Templates
 */
public class ConditionRulePanel extends JPanel {

    /**
     *  
     */
    private RuleTreePanel parent_panel_;

    private SensorChoosePanel left_sensor_;

    private SensorChoosePanel right_sensor_;

    private SensorChoosePanel ahead_sensor_;

    private CurrentSensorPanel current_sensor_;

    private ConditionChoosePanel cond_panel_;

    private JCheckBox active_switch_;

    private JButton delete_button_;

    private HashMap brick_images_;

    /** Drop related classes */
    private DropRuleListener drop_rule_listener_;

    private DropTarget drop_target_;

    private int acceptable_actions_ = DnDConstants.ACTION_COPY;

    private int id_;

    ActionRulePanel new_action_;

    private boolean action_added_;

    public ConditionRulePanel() {
        super();
        this.setLayout(null);
        drop_rule_listener_ = new DropRuleListener();
        drop_target_ = new DropTarget(this, this.acceptable_actions_,
                this.drop_rule_listener_, true);
        action_added_ = false;
    }

    public ConditionRulePanel(int id, RuleTreePanel parent_panel,
            HashMap brick_images) {

        super();
        this.setLayout(null);
        action_added_ = false;
        id_ = id;
        parent_panel_ = parent_panel;
        brick_images_ = brick_images;

        left_sensor_ = new SensorChoosePanel(brick_images);
        right_sensor_ = new SensorChoosePanel(brick_images);
        ahead_sensor_ = new SensorChoosePanel(brick_images);
        cond_panel_ = new ConditionChoosePanel(brick_images, true);
        current_sensor_ = new CurrentSensorPanel(brick_images);

        initComponents();
        initActionListener();
    }

    /**
     * This constructor is just for loading predefined rules <
     * 
     * @param id
     * @param parent_panel
     * @param brick_images
     * @param preset_ahead_sensor
     * @param preset_left_sensor
     * @param preset_right_sensor
     * @param preset_current_sensor
     * @param preset_state
     * @param preset_action_direction
     * @param preset_action_current_sensor
     * @param preset_action_state
     */
    public ConditionRulePanel(int id, RuleTreePanel parent_panel,
            HashMap brick_images, int preset_ahead_sensor,
            int preset_left_sensor, int preset_right_sensor,
            int preset_current_sensor, int preset_state,
            int preset_action_direction, int preset_action_current_sensor,
            int preset_action_state) {

        super();
        this.setLayout(null);
        action_added_ = true;
        id_ = id;
        parent_panel_ = parent_panel;
        brick_images_ = brick_images;

        left_sensor_ = new SensorChoosePanel(brick_images, preset_left_sensor);
        right_sensor_ = new SensorChoosePanel(brick_images, preset_right_sensor);
        ahead_sensor_ = new SensorChoosePanel(brick_images, preset_ahead_sensor);

        cond_panel_ = new ConditionChoosePanel(brick_images, preset_state, true);

        current_sensor_ = new CurrentSensorPanel(brick_images,
                preset_current_sensor);
        new_action_ = new ActionRulePanel("PRESET_ACTION", brick_images_,
                preset_action_direction, preset_action_current_sensor,
                preset_action_state);
        this.add(new_action_);
        new_action_.setBounds(80, 25, 165, 50);
        initComponents();
        initActionListener();
    }

    void initComponents() {

        this.setLayout(null);

        drop_rule_listener_ = new DropRuleListener();
        drop_target_ = new DropTarget(this, this.acceptable_actions_,
                this.drop_rule_listener_, true);

        JLabel top_label = new JLabel();
        JLabel csensor_label = new JLabel();
        active_switch_ = new JCheckBox();
        delete_button_ = new JButton();

        this.add(top_label);
        this.add(left_sensor_);
        this.add(right_sensor_);
        this.add(ahead_sensor_);
        this.add(csensor_label);
        this.add(current_sensor_);
        this.add(active_switch_);
        this.add(delete_button_);
        this.add(cond_panel_);

        left_sensor_.setBounds(10, 40, 20, 20);
        ahead_sensor_.setBounds(32, 18, 20, 20);
        right_sensor_.setBounds(54, 40, 20, 20);
        current_sensor_.setBounds(32, 40, 20, 20);
        cond_panel_.setBounds(27, 62, 30, 15);

        top_label.setText("Sensorregel:");
        //top_label.setForeground( Color.white );

        //csensor_label.setText("Bodensensor:");

        top_label.setBounds(5, 2, 150, 15);
        active_switch_.setBounds(210, 2, 20, 20);
        active_switch_.setOpaque(false);
        active_switch_.setSelected(true);

        delete_button_.setBounds(230, 6, 13, 13);
        delete_button_.setOpaque(false);
        delete_button_.setIcon((ImageIcon) brick_images_.get("X_BUTTON"));

        this.setBorder(new javax.swing.border.SoftBevelBorder(
                javax.swing.border.BevelBorder.RAISED));
        this.setBackground(Color.GRAY);
    }

    public int getID() {
        return id_;
    }

    private void initActionListener() {
        active_switch_.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                if (active_switch_.isSelected())
                    ConditionRulePanel.this.setBackground(Color.GRAY);
                else
                    ConditionRulePanel.this.setBackground(Color.DARK_GRAY);
            }
        });
        delete_button_.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                parent_panel_.deleteRule(id_);
            }
        });

    }

    public Instruction getInstruction() {
        // Instruction instruction = new Instruction(new Condition(0, 0, true,
        // true, false),
        //        new Action(0, 0, Action.MOVE_AHEAD));

        if ((active_switch_.isSelected()) && (action_added_ == true)) {
            boolean left_sensor_bool, right_sensor_bool, ahead_sensor_bool;

            if (ahead_sensor_.getInternalState() == SensorChoosePanel.FREE)
                ahead_sensor_bool = false;
            else
                ahead_sensor_bool = true;

            if (left_sensor_.getInternalState() == SensorChoosePanel.FREE)
                left_sensor_bool = false;
            else
                left_sensor_bool = true;

            if (right_sensor_.getInternalState() == SensorChoosePanel.FREE)
                right_sensor_bool = false;
            else
                right_sensor_bool = true;

            Condition ret_condition = new Condition(cond_panel_
                    .getInternalState(), current_sensor_.getInternalState(),
                    left_sensor_bool, right_sensor_bool, ahead_sensor_bool);
            Action ret_action = new_action_.getAction();

            return new Instruction(ret_condition, ret_action);

        } else
            return null;

    }

    public void addAction(String name) {

        if (name.compareTo("ConditionRule") == 0) {
            //System.out.println("Depp bläder");
        } else {
            if (!action_added_) {
                new_action_ = new ActionRulePanel(name, brick_images_,
                        DirectionChoosePanel.UP,
                        CurrentSensorPanel.EMPTY_FLOOR,
                        ConditionChoosePanel.NONE);
                this.add(new_action_);
                new_action_.setBounds(80, 25, 165, 50);
                action_added_ = true;
            }
        }
    }

    public class DropRuleListener implements DropTargetListener {

        /**
         * Called by isDragOk Checks to see if the flavor drag flavor is
         * acceptable
         * 
         * @param e
         *            the DropTargetDragEvent object
         * @return whether the flavor is acceptable
         */
        private boolean isDragFlavorSupported(DropTargetDragEvent e) {
            boolean ok = false;
            if (e.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                ok = true;
            } else if (e.isDataFlavorSupported(DataFlavor.plainTextFlavor)) {
                ok = true;
            }
            return ok;
        }

        /**
         * Called by drop Checks the flavors and operations
         * 
         * @param e
         *            the DropTargetDropEvent object
         * @return the chosen DataFlavor or null if none match
         */
        private DataFlavor chooseDropFlavor(DropTargetDropEvent e) {
            DataFlavor chosen = null;
            if (e.isLocalTransfer() == true)
                if (e.isDataFlavorSupported(DataFlavor.stringFlavor)) {
                    chosen = DataFlavor.stringFlavor;
                } else if (e.isDataFlavorSupported(DataFlavor.plainTextFlavor)) {
                    chosen = DataFlavor.plainTextFlavor;
                }
            return chosen;
        }

        /**
         * Called by dragEnter and dragOver Checks the flavors and operations
         * 
         * @param e
         *            the event object
         * @return whether the flavor and operation is ok
         */
        private boolean isDragOk(DropTargetDragEvent e) {
            if (isDragFlavorSupported(e) == false) {
                // System.out.println( "isDragOk:no flavors chosen" );
                return false;
            }
            int da = e.getDropAction();
            // System.out.print("dt drop action " + da);
            // System.out.println(" my acceptable actions " +
            // acceptable_actions_);
            if ((da & ConditionRulePanel.this.acceptable_actions_) == 0)
                return false;
            return true;
        }

        /**
         * start "drag under" feedback on component invoke acceptDrag or
         * rejectDrag based on isDragOk
         */
        public void dragEnter(DropTargetDragEvent e) {
            // System.out.println( "dtlistener dragEnter");
            if (isDragOk(e) == false) {
                // System.out.println( "enter not ok");
                // CODE HERE if bad
                e.rejectDrag();
                return;
            }
            // CODE HERE if good
            // System.out.println( "dt enter: accepting " + e.getDropAction());
            e.acceptDrag(e.getDropAction());
        }

        /**
         * continue "drag under" feedback on component invoke acceptDrag or
         * rejectDrag based on isDragOk
         */
        public void dragOver(DropTargetDragEvent e) {
            if (isDragOk(e) == false) {
                // System.out.println( "dtlistener dragOver not ok" );
                // CODE IF NESSECARY
                e.rejectDrag();
                return;
            }
            // System.out.println( "dt over: accepting");
            e.acceptDrag(e.getDropAction());
        }

        public void dropActionChanged(DropTargetDragEvent e) {
            if (isDragOk(e) == false) {
                // System.out.println( "dtlistener changed not ok" );
                e.rejectDrag();
                return;
            }
            // System.out.println( "dt changed: accepting"+e.getDropAction());
            e.acceptDrag(e.getDropAction());
        }

        public void dragExit(DropTargetEvent e) {
            // System.out.println( "dtlistener dragExit");
        }

        /**
         * perform action from getSourceActions on the transferrable invoke
         * acceptDrop or rejectDrop invoke dropComplete if its a local (same
         * JVM) transfer, use StringTransferable.localStringFlavor find a match
         * for the flavor check the operation get the transferable according to
         * the chosen flavor do the transfer
         */
        public void drop(DropTargetDropEvent e) {
            // System.out.println( "dtlistener drop");
            DataFlavor chosen = chooseDropFlavor(e);
            if (chosen == null) {
                // System.err.println( "No flavor match found" );
                e.rejectDrop();
                return;
            }
            // System.err.println( "Chosen data flavor is " +
            // chosen.getMimeType());
            int da = e.getDropAction();
            int sa = e.getSourceActions();
            // System.out.println( "drop: sourceActions: " + sa);
            // System.out.println( "drop: dropAction: " + da);

            if ((sa & ConditionRulePanel.this.acceptable_actions_) == 0) {
                // System.err.println( "No action match found" );
                e.rejectDrop();
                // CODE
                return;
            }

            Object data = null;
            try {
                e.acceptDrop(ConditionRulePanel.this.acceptable_actions_);
                data = e.getTransferable().getTransferData(chosen);
                if (data == null)
                    throw new NullPointerException();
            } catch (Throwable t) {
                // System.err.println( "Couldn't get transfer data: " +
                // t.getMessage());
                t.printStackTrace();
                e.dropComplete(false);
                // Bad transdata
                return;
            }
            // System.out.println( "Got data: " + data.getClass().getName() );

            if (data instanceof String) {
                String s = (String) data;
                //DropLabel.this.setText(s);

                // TODO ACTION
                ConditionRulePanel.this.addAction(s);

            } else if (data instanceof InputStream) {
                InputStream input = (InputStream) data;
                InputStreamReader isr = null;
                //	BufferedReader br = null;
                try {
                    // br = new BufferedReader(isr=new
                    // InputStreamReader(input,"Unicode"));
                    isr = new InputStreamReader(input, "Unicode");
                } catch (UnsupportedEncodingException uee) {
                    isr = new InputStreamReader(input);
                }

                StringBuffer str = new StringBuffer();
                int in = -1;
                try {
                    while ((in = isr.read()) >= 0) {
                        //// System.out.println("read: " + in);
                        if (in != 0)
                            str.append((char) in);
                    }

                    /*
                     * you get garbage chars this way try { String line=null;
                     * while( (line = br.readLine()) != null) {
                     * str.append(line); str.append('\n'); //
                     * System.out.println( "read: " + line); //
                     * System.out.println( "read: " +
                     * (int)line.charAt(line.length()-1)); }
                     * 
                     * br.close();
                     */
                    // CODE HERE DATA FROM STREAM
                    //DropLabel.this.setText(str.toString());
                } catch (IOException ioe) {
                    /*
                     * bug #4094987 sun.io.MalformedInputException: Missing
                     * byte-order mark e.g. if dragging from MS Word 97 still a
                     * bug in 1.2 final
                     */

                    // System.err.println( "cannot read" + ioe);
                    e.dropComplete(false);

                    String message = "Bad drop\n" + ioe.getMessage();
                    // System.err.println(message);
                }

            } else {
                // System.out.println( "drop: rejecting");
                e.dropComplete(false);

                return;
            }

            e.dropComplete(true);

        }

    }

}
