/*
 * Copyright (c) 2006 Stanford University.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Stanford University nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL STANFORD
 * UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package net.tinyos.mviz;

// DDocument.java

import java.awt.*;

import javax.imageio.ImageIO;
import javax.swing.*;

import java.util.*;
import java.awt.event.*;
import java.io.*;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.table.*;

import java.awt.image.*;


// Standard imports for XML
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.w3c.dom.*;




public class DLayer extends JPanel implements ActionListener{
	
    public static final int MOTE = 0;
    public static final int LINK = 1;
    public static final int FIELD = 2;
    private static final Color[] COLORS = {
	new Color(231, 220, 206),
	new Color(250, 210, 99),
	new Color(209, 230, 179)
    };
	
    private int type;
    protected int index;
    protected int zIndex;
    protected int z_index = 0;
    private ArrayList layer = new ArrayList();
	
    private JLabel label;
    private JCheckBox check;
    private String[][] DISPLAYS = { {"circle", "img", "txt"}, {"line", "line+label", "label"}, {"color 256", "color 1024", "color 4096", "color 16384"}};
    private JComboBox displays;
	
    private ArrayList models;
    private ArrayList linkModels;
    private JButton up;
    private JButton down;
	
    protected int paintMode = 0;
    // Values chosen for COLOR so that readings can be right shifted
    // that many bits to be in range 0-255
    static public final int COLOR_256 = 0;
    static public final int OVAL = 1;
    static public final int COLOR_1024 = 2;
    static public final int IMG = 3;
    static public final int COLOR_4096 = 4;
    static public final int TXT_MOTE = 5;
    static public final int COLOR_16384 = 6;
    static public final int LINE = 7;
    static public final int LABEL = 8;
    static public final int LINE_LABEL = 9;
    
    protected DNavigate navigator;
	
    private String name;
    private DDocument parent;
	
    public DLayer(int zIndex, int index, String label, int type, DDocument parent, ArrayList models, DNavigate navigator){
	this.parent = parent;
	this.type = type;
	this.models = models;
	this.zIndex = zIndex;
	this.index = index;
	this.navigator = navigator;
	this.name = label;
	if (type == MOTE) {
	    this.paintMode = OVAL;
	}
	else if (type == LINK) {
	    this.paintMode = LINE;
	}

	
	SpringLayout layout = new SpringLayout();
	setLayout(layout);
	setMaximumSize(new Dimension(350, 25));
	setPreferredSize(new Dimension(350, 25));
	setSize(new Dimension(350, 25));
	setDoubleBuffered(true);
	setBackground(COLORS[type]);
	setBorder(new LineBorder(new Color(155, 155, 155)));
		
	check = new JCheckBox();
	check.setSize(35, 25);
	check.setMaximumSize(new Dimension(35, 25));
	check.setMinimumSize(new Dimension(35, 25));
	check.setPreferredSize(new Dimension(35, 25));
	
	up = new JButton("^");
	up.setFont(new Font("Times", Font.PLAIN, 9));
	up.setSize(25, 25);
	up.setMaximumSize(new Dimension(25, 25));
	up.setMinimumSize(new Dimension(25, 25));
	up.setPreferredSize(new Dimension(25, 25));
	up.setMargin(new Insets(2, 2, 2, 2));

	down = new JButton("v");
	down.setFont(new Font("Times", Font.PLAIN, 8));
	down.setSize(25, 25);
	down.setMaximumSize(new Dimension(25, 25));
	down.setMinimumSize(new Dimension(25, 25));
	down.setPreferredSize(new Dimension(25, 25));
	down.setMargin(new Insets(2, 2, 2, 2));

	this.label = new JLabel(" " + label, JLabel.LEFT);
	this.label.setSize(125, 25);
	this.label.setMaximumSize(new Dimension(125, 25));
	this.label.setMinimumSize(new Dimension(125, 25));
	this.label.setPreferredSize(new Dimension(125, 25));
	switch (type) {
	case MOTE:
	    this.label.setBackground(new Color(255, 200, 200));
	    break;
	case FIELD:
	    this.label.setBackground(new Color(200, 255, 200));
	    break;
	case LINK:
	    this.label.setBackground(new Color(200, 200, 255));
	    break;
	default:
	    // do nothing
	}
	
	displays = new JComboBox(DISPLAYS[type]);
	displays.setSize(100, 25);
	//displays.setMaximumSize(new Dimension(125, 25));
	displays.setMinimumSize(new Dimension(125, 25));
	displays.setPreferredSize(new Dimension(125, 25));
	
	
	check.addActionListener(this);
	up.addActionListener(this);
	down.addActionListener(this);
	displays.addActionListener(this);

	layout.putConstraint(SpringLayout.WEST, this, 0, SpringLayout.WEST, down);
	layout.putConstraint(SpringLayout.EAST, check, 0, SpringLayout.WEST, down);
	layout.putConstraint(SpringLayout.EAST, down, 0, SpringLayout.WEST, up);
	layout.putConstraint(SpringLayout.EAST, up, 0, SpringLayout.WEST, this.label);
	layout.putConstraint(SpringLayout.EAST, this.label, 0, SpringLayout.WEST, displays);
	layout.putConstraint(SpringLayout.EAST, displays, 0, SpringLayout.EAST, this);

	
	add(check);
	add(down);
	add(up);
	add(this.label);
	add(displays);

	
		
    }
	
    public boolean isFieldSelected(){
	return (type==FIELD && check.isSelected());
    }
	
    public void actionPerformed(ActionEvent e) {
	if (e.getSource() == check) {
	    if (check.isSelected()){
		parent.selectedFieldIndex = index;
		//repaintLayer(g);
		//System.out.println("redraw index " +zIndex +" on layer");
	    } else if(type==FIELD){
		//System.out.println("clear");
		//parent.canvas.repaint();
		//repaintLayer(g);
	    } else {
		//repaintLayer(g);
	    }
	} else if (e.getSource() == up){
	    parent.navigator.moveLayerUp(this.zIndex);
	} else if (e.getSource() == down){
	    parent.navigator.moveLayerDown(this.zIndex);
	} else if (e.getSource() == displays){
	    String selected = (String)displays.getSelectedItem();
	    if (selected.equals("circle")){
		paintMode = OVAL;
	    } else if (selected.equals("img")){
		paintMode = IMG;        		
	    } else if (selected.equals("txt")){
		paintMode = TXT_MOTE;        		
	    } else if (selected.equals("color 256")) {
		paintMode = COLOR_256;
	    } else if (selected.equals("color 1024")) {
		paintMode = COLOR_1024;
	    } else if (selected.equals("color 4096")) {
		paintMode = COLOR_4096;
	    } else if (selected.equals("color 16384")) {
		paintMode = COLOR_16384;
	    } else if (selected.equals("line")) {
		paintMode = LINE;
	    } else if (selected.equals("label")) {
		paintMode = LABEL;
	    } else if (selected.equals("line+label")) {
		paintMode = LINE_LABEL;
	    }
	}
	//System.out.println("Repainting parent?");
	//parent.repaint();
    }

    public void init(){
	if (type==LINK){
	    //addLinks(true);
	} else {
	    addMotes(true);
	}
    }

    public String toString() {
	return "Layer " +  name + " " + type;
    }
    
	
    // private void addLinks(boolean paint){
    // 		Iterator it = models.iterator();
    // 		while(it.hasNext()){
    // 			DLink mm = (DLink) it.next();
    // 			//canvas.add(mm);
    // 			if (paint) mm.repaint();
    // 		}    	
    //     }
	
    protected void addMote(DMoteModel model, boolean paint){
	DShape mote = new DMote(model, this.parent, this);
	layer.add(mote);
    }
	
    private void addMotes(boolean paint){
	Iterator it = models.iterator();
        while(it.hasNext()){
	    addMote((DMoteModel) it.next(), paint);
	} 	    
    }
    
	
    public void updateIndex(int index, boolean repaint){
	zIndex = index;
	z_index = (navigator.totalLayers - zIndex)*100;
	//if (repaint) redrawLayer();
	//parent.canvas.setLayer(d.canvas, length - i);
    }

    public void paintScreenBefore(Graphics g) 
    {

        Dimension d = parent.canvas.getSize();
        int x = 0;
        int y = 0;
        int xstep = (int)(d.width / 40);
	int ystep = (int)(d.height / 40);  

        for(;x < d.width; x += xstep){
            for(y = 0;y < d.height; y += ystep){
                double val = 0;
                double sum = 0;
                double total = 0;
                double min = 10000000;
                Iterator it = models.iterator();
                while(it.hasNext()){
                    DMoteModel m = (DMoteModel) it.next();
                    double dist = distance(x, y, m.x, m.y);   
                    if(true){ //121
                        if(dist < min) min = dist;
                        val += ((double)(((int)m.getValue(index)) >> paintMode ))  / dist /dist;
                        sum += (1/dist/dist);
                    }
                }
                int reading = (int)(val / sum);
		//System.out.println("Reading: " + reading);
                if (reading > 255)
                    reading = 255;
                g.setColor(new Color(reading, reading, reading));
		//System.out.println("Filling "  + x + "+" + step + " " + y + "+" + step + " with " + g.getColor());
                g.fillRect(x, y, xstep, ystep);
            }
        }

	
    }

    public double distance(int x, int y, int x1, int y1){
        return Math.sqrt( (x-x1)*(x-x1)+(y-y1)*(y-y1));
    }

    protected void repaintLayer(Graphics g){
    	if (check.isSelected()){
	    //System.out.println("Repaint layer " + name);
	    if 	(type==FIELD){
		paintScreenBefore(g);
	    } else if (type == LINK) {
		Iterator it = models.iterator();
		//System.out.print("Draw links: ");
		while (it.hasNext()) {
		    DLinkModel model = (DLinkModel)it.next();
		    DLink lnk = new DLink(model, parent, this);
		    lnk.paintShape(g);
		    //System.out.print("+");
		}
		//System.out.println();
	    }
	    else if (type == MOTE) {
		Iterator it = models.iterator();
		//System.out.print("Draw motes: ");
		while (it.hasNext()){
		    DMoteModel model = (DMoteModel)it.next();
		    DShape m = new DMote(model, parent, this);
		    m.paintShape(g);
		    //System.out.print("+");
		}
		//System.out.println();
	    }
    	}	
    }
}
