package unileipzig.isys.neuronviz.kernel;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.util.Vector;

import javax.swing.JComponent;

/**
 * Class SynapseComponent
 */
public class SynapseComponent extends JComponent {
  private Point startPoint, endPoint;
  private String synapseName;
  private double outputValue;
  private Vector inputValueList, inputNeuronList;
  private boolean activationVisibility = false;

  public SynapseComponent() {
    inputValueList = new Vector();
    inputNeuronList = new Vector();
    setLayout(null);
    setPreferredSize(new Dimension(600, 20));
    setBounds(getLocation().x, getLocation().y, 601, 21);
    endPoint = startPoint = new Point(0, 0);
  }

  public void paintComponent(Graphics g) {
    // use the extended possibilities of Graphics2D
    Graphics2D g2 = (Graphics2D) g;
    // switch on antialising for pretty rendering results
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    // draw a visualization of the inputs
    Object[] obj = inputNeuronList.toArray();
    for(int i=0; i<obj.length; i++) {
      // find minimum (smallest x position) in the neuron list
      int min = Integer.MAX_VALUE;
      int min_index = -1;
      for(int j=0; j<obj.length; j++) {
        if(obj[j] == null) continue;
        int x = ((SynapseComponent)(obj[j])).getX();
        if(x < min) {
          min = x;
          min_index = j;
        }
      }
      obj[min_index] = null;
      double value = ((Double)(inputValueList.get(min_index))).doubleValue();
      // use a color that indicates the activation level
      g2.setColor(getSynapseColor(value));
      g2.fillRect(i*20 + 1, 1, 19, 19);
    }
  }

  /**
   * Get a color representation of parameter value
   * @param value
   * @return
   */
  private Color getSynapseColor(double value) {
    Color col;
    int c = (int)(255*value);
    if(c>767) c = 767;
    if(c<-767) c = -767;

    //                   cyan -> blue	(-512 to -767)
    if(c<-511) col = new Color(0, 767+c, 255);
    //          green -> cyan		(-256 to -511)
    else if(c<-255) col = new Color(0, 255, -256-c);
    // white -> green			(-1 to -255)
    else if(c<0)  col = new Color(255+c, 255, 255+c);
    //          yellow -> orange -> red	(256 to 767)
    else if(c>255) col = new Color(255, 383-c/2, 0);
    // white -> yellow			(0 to 255)
    else col = new Color(255, 255, 255-c);

    return col;
  }

  /**
   * Deletes the input lists. This has to be done before a new channel data line is read.
   * After deleting the old inputs the new inputs of the new data line can be inserted.
   */
  public void clearInputList() {
    inputValueList.clear();
    inputNeuronList.clear();
  }

  /**
   * Adds a new input to the neuron. The input can now be visualized after repainting the component.
   * @param value
   */
  public void addInputValue(double value, SynapseComponent fromNeuron) {
    inputValueList.add(new Double(value));
    inputNeuronList.add(fromNeuron);
  }

  /////////////////////////////////
  // {{{ Getter- and Setter-Methods
  public String getSynapseName() {
    return synapseName;
  }

  public void setSynapseName(String synapseName) {
    this.synapseName = synapseName;
  }

  public double getOutputValue() {
    return outputValue;
  }

  public void setOutputValue(double outputValue) {
    this.outputValue = outputValue;
  }

  public boolean isActivationVisibility() {
    return activationVisibility;
  }

  public void setActivationVisibility(boolean activationVisibility) {
    this.activationVisibility = activationVisibility;
  }
  // Getter- and Setter-Methods }}}
  /////////////////////////////////
}
