//
// Visuzalization module for TETDM 
// ScoreNetwork.java Version 0.30
// Copyright(C) 2011 WATARU SUNAYAMA ALL RIGHTS RESERVED.
//
// This program is provided under the license.
// You should read the README file.
//


//setData, setScoreData: differences between this and drawOriginal

package module.VisualizationModules.ScoreNetwork;

import source.*;
import source.TextData.*;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;


public class ScoreNetwork extends VisualizationModule implements MouseListener, MouseMotionListener
{
	//For objects operation
	int mousex, mousey;			//Coordinates for a mouse
	int old_mousex, old_mousey;	//Last Coordinates for a mosue
	int dx, dy;					//Distance for mouse moving
	
	int touch_num;				//Node Number of being touched
	int lastTouchNumber;		//Node Number of last touched
	int oldTouchNumber;
	
	boolean moving;			//Flag for node moving
	boolean dragging;		//Flag for field moving	

	boolean normalColor;
	
	int node_keyidlist[];
	int topic_num;
	
	DecimalFormat df_a;
	
	NewMapData2 map;
	
	public ScoreNetwork()
	{
		setModuleID(6);
        dataNumbers = new int[]{1,0,0,0,    // b,i,d,S
            0,0,1,0,    // bA,iA,dA,SA
            0,0,0};     // bA2,iA2,dA2
	}

	public void initializePanel()
	{
		addMouseListener(this);			//MouseListener
		addMouseMotionListener(this);	//MouseMotionListener	
	}	
	
	public void initializeData()
	{
		normalColor = true;
		df_a = new DecimalFormat("00");
		
		touch_num = -1;
		lastTouchNumber = -1;
		
		moving = false;
		dragging = false;
		
		topic_num = 0;
		
		map = new NewMapData2(text.segmentRelation.number);		
	}
	
	public void displayOperations(int optionNumber)
	{
		switch(optionNumber)
		{
			case 4501:	
			case 0:
				boolean active[] = new boolean[text.segmentNumber];
				for(int i=0;i<text.segmentNumber;i++)
					active[i] = true;
				
				text.segmentRelation.createStrongestLink(text.segmentRelation.cos);
				//		text.segmentRelation.optimize_link(text.segmentRelation.cos, 0.5);		
				
				map.set_relation_data(text.segmentRelation);
//saveData();
				repaint();
				break;
				
			case 1:
				text.segmentRelation.createStrongestLink(text.segmentRelation.cos);				
				map.set_relation_data(text.segmentRelation);				
				
				for(int i=0;i<text.segmentNumber;i++)
					map.node[i].score = map.relation[i][0].value;
				map.calculateSvalue();
				normalColor=true;
				
				
				break;
				
			case 11:
				saveData();
				break;
		}		
	}

	public boolean setData(int dataID, double score[])
	{
        if(score.length != text.segmentNumber)
            return false;
     
		switch(dataID)
		{
			case 0:
				map.setScoreData(score);
				map.calculateSvalue();
				return true;
		}
		return false;
	}
	
	public boolean setData(int dataID, boolean color)
	{
		switch(dataID)
		{
			case 0:
				normalColor = color;
				repaint();
				return true;
		}
		return false;
	}
	
	public void saveData()
	{
		String datafile = "ScoreData";
		String saveFile = myModulePath+datafile;
		String saveData[];
		
		saveData = new String[text.segmentNumber];
		
		for(int i=0;i<text.segmentNumber;i++)
			saveData[i] = map.node[i].name+" "+map.node[i].score;

		fileWriteArray(saveFile, saveData, saveData.length);			
	}

	//////////DRAWING

	
	void calcu_coordinate()
	{
		for(int i=0;i<text.segmentNumber;i++)
		{
			map.node[i].x *= changeX;
			map.node[i].y *= changeY;
		}
	}	
	
	void draw_background(Graphics2D g2)
	{
		int y40 = (int)(((40 - map.minSvalue) / (map.maxSvalue - map.minSvalue)) * (sizeY - 100)) + 50;
		int y60 = (int)(((60 - map.minSvalue) / (map.maxSvalue - map.minSvalue)) * (sizeY - 100)) + 50;		
		
//			System.out.println(" y40, y60 = "+y40+" : "+y60);		
		
		if(normalColor)
		{
			g2.setColor(new Color(0,128,255));
			g2.fillRect(0,0, sizeX, y40);
		
			g2.setColor(Color.yellow);
			g2.fillRect(0,y40, sizeX, y60);
		
			g2.setColor(Color.red);
			g2.fillRect(0,y60, sizeX, sizeY);
		}
		else
		{
			g2.setColor(Color.red);
			g2.fillRect(0,0, sizeX, y40);
			
			g2.setColor(Color.yellow);
			g2.fillRect(0,y40, sizeX, y60);
			
			g2.setColor(new Color(0,128,255));			
			g2.fillRect(0,y60, sizeX, sizeY);			
		}

	}

	//Display links
	public void draw_links(Graphics2D g2)
	{
		g2.setColor(Color.white);
		g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER));
		for(int i=0;i<map.node_num;i++)
			for(int j=0;j<map.node_num;j++)
				if(map.relation[i][j].link == true)
					g2.drawLine((int)map.node[i].x,(int)map.node[i].y,(int)map.node[j].x,(int)map.node[j].y);
	}
	
	
	//Display nodes
	public void draw_node(Graphics2D g2, int n)
	{
		g2.setColor(map.node[n].color);
		g2.fillOval((int)map.node[n].x - (int)map.node[n].radius, 
						(int)map.node[n].y - (int)map.node[n].radius, (int)map.node[n].radius*2, (int)map.node[n].radius*2);
	}
	
	public void draw_nodes(Graphics2D g2)
	{
		for(int i=0;i<map.node_num;i++)
			draw_node(g2, i);
	}
	
	////Dispaly node names
	public void draw_node_name(Graphics2D g2, int n)
	{
		g2.setFont(new Font("Dialog", Font.BOLD, (int)(text.fontSize+10-2*map.node_num/25.0)));
		g2.drawString(map.node[n].name, (int)map.node[n].x+(int)map.node[n].radius, (int)map.node[n].y+(int)map.node[n].radius);	
	}
	
	////Dispaly node names
	public void drawNodeNameWithValues(Graphics2D g2, int n)
	{
		g2.setFont(new Font("Dialog", Font.BOLD, (int)(text.fontSize+10-2*map.node_num/25.0)));		
		g2.drawString(map.node[n].name+"("+df_a.format(map.node[n].score)+":"+df_a.format(map.node[n].svalue)+")", (int)map.node[n].x+(int)map.node[n].radius, (int)map.node[n].y+(int)map.node[n].radius);	
	}
	
	public void draw_node_names(Graphics2D g2)
	{		
		for(int i=0;i<map.node_num;i++)
		{
			g2.setColor(Color.black);
			draw_node_name(g2, i);
		}
	}	
	
	public void draw_touch_node(Graphics2D g2)
	{
		if(text.focus.mainFocusSegment < 0)
			return;
		
		draw_node(g2, text.focus.mainFocusSegment);
	}
	
	//Display node names touched by a mouse
	public void draw_touch_nodename(Graphics2D g2)
	{
		if(text.focus.mainFocusSegment < 0)
			return;
	
		int i=text.focus.mainFocusSegment, j=text.segmentRelation.rank[text.focus.mainFocusSegment][1];
		
		g2.setColor(Color.white);
		g2.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND,BasicStroke.JOIN_MITER));
		g2.drawLine((int)map.node[i].x,(int)map.node[i].y,(int)map.node[j].x,(int)map.node[j].y);		
		
		
		g2.setColor(Color.green);
		drawNodeNameWithValues(g2, i);
		drawNodeNameWithValues(g2, j);
	}


	
	
	public void paintComponent(Graphics g)
	{
        if(checkDataNumbers() == false)
            return;
		
		Graphics2D g2 = (Graphics2D)g;
		
		boolean change = getPanelSize();		
		
		if(change)
			calcu_coordinate();
		
		draw_background(g2);	//Set background
		draw_links(g2);			//Display links
		draw_nodes(g2);			//Display nodes
		draw_node_names(g2);	//Display node names
		draw_touch_node(g2);	//Display nodes touched by a mouse
		draw_touch_nodename(g2);	//Display node names touched by a mouse
//		draw_parameters(g2);	//Display parameters
		

	}
	
	public void update(Graphics g)		//Avoid from blinking
	{
		paintComponent(g);
	}
	
	//MouseListener
	public void mousePressed(MouseEvent me)	//Press
	{
		mousex = me.getX();
		mousey = me.getY();
		
		if(touch_num == -1)
		{
			old_mousex = mousex;
			old_mousey = mousey;
			dragging = true;
			return;
		}
		moving = true;
	}
	
	public void mouseReleased(MouseEvent me)	//Release
	{
		if(moving == true)
			moving = false;
		
		if(dragging == true)
			dragging = false;
	}
	
	public void mouseEntered(MouseEvent me){}	//Enter an area
	public void mouseExited(MouseEvent me){}	//Exit an area
	
	public void mouseClicked(MouseEvent me){}	//Click


	
	//MouseMotionListener
	public void mouseDragged(MouseEvent me)	//Dragging
	{
		if(moving == true)		//Move a node
		{
			try{
				mousex = me.getX();
				mousey = me.getY();
				
				map.node[touch_num].x = mousex;
				map.node[touch_num].y = mousey;
				
				repaint();
			}
			catch(StackOverflowError e){
				System.out.println("Stack OVERFLOW");
			}
		}
		
		if(dragging == true)	//Move Field
		{
			mousex = me.getX();
			mousey = me.getY();
			dx = old_mousex - mousex;
			dy = old_mousey - mousey;
			old_mousex = mousex;
			old_mousey = mousey;
			
			for(int i=0;i<map.node_num;i++)
			{
				map.node[i].x -= dx;
				map.node[i].y -= dy;
			}
			repaint();
		}
	}
	
	public void mouseMoved(MouseEvent me)
	{
		mousex = me.getX();
		mousey = me.getY();
		touch_num = CatchNode(mousex,mousey);
		
		if(touch_num == lastTouchNumber)
			return;
		
		lastTouchNumber = touch_num;

		if(touch_num >= 0)
		{
			text.focus.mainFocusSegment = touch_num;
			text.focus.subFocusSegment = text.segmentRelation.rank[touch_num][1];//
			
			if(touch_num != oldTouchNumber)
			{
				repaintOthersByTouch();
				executeAllByTouch();
				oldTouchNumber = touch_num;
			}
			repaint();
		}
	}
	
	public int CatchNode(int mousex, int mousey)	//Investigate number of selected node
	{
		for(int i=0;i<map.node_num;i++)
			if((mousex > map.node[i].x - map.node[i].radius && mousex < map.node[i].x + map.node[i].radius 
												+ map.node[i].name.length()*(24-2*map.node_num/25.0)) && 
			   (mousey > map.node[i].y - map.node[i].radius && mousey < map.node[i].y + map.node[i].radius))
				return i;
	 
		return -1;
	}
	

	

	class NewMapData2
	{
		
		class Node
		{
			String name;
			int id;
		
			double x;
			double y;
			double radius=10;
			
			double score;
			double svalue;
			
			int link_num;
		
			Color color;
		}
	
		Node node[];
		int node_num;
		
		double minSvalue;
		double maxSvalue;
	
	
		//Node Relation Class
		class Relation
		{
			boolean link;			//Is exist a link between nodes?
			double value;
		}
	
		Relation relation[][];		//Node Relation information	

		NewMapData2(int num)
		{
			init_nodes(num);
		}		
		
		void init_nodes(int num)
		{
			node_num = num;
			node = new Node[node_num];
		
			for(int i=0;i<node_num;i++)
				node[i] = new Node();
		
			relation = new Relation[node_num][node_num];

			for(int i=0;i<node_num;i++)
				for(int j=0;j<node_num;j++)
					relation[i][j] = new Relation();
		}

		void set_relation_data(RelationalData rd)
		{
			for(int i=0;i<node_num;i++)
				for(int j=0;j<node_num;j++)
				{
					relation[i][j].link = rd.link[i][j];
					relation[i][j].value = rd.value[i];				
				}
			
			for(int i=0;i<node_num;i++)
			{
				node[i].id = i;
				node[i].name = rd.name[i];
				node[i].x = 50 + (sizeX - 100) * i/node_num;
				node[i].color = new Color(0xff,0x66,0x00);			
			}			
		}


		
		void setScoreData(double score[])
		{
			for(int i=0;i<node_num;i++)
				node[i].score = score[i];
		}
		
		//svalue
		
		void calculateSvalue()// This is not used if all values are the same (might be occurred when a word appears all segments and used conditional probs)
		{
			double max = node[0].score;
			
			for(int i=1;i<node_num;i++)
				if(node[i].score > max)
					max = node[i].score;
			
			
			
			double average,average2;
			double std;
			
			average = average2 = 0.0;
			
			for(int i=0;i<node_num;i++)
			{
				average += node[i].score;
				average2 += node[i].score * node[i].score;
			}
			average /= node_num;
			average2 /= node_num;
			
			std = Math.sqrt(average2 - average*average);
			
			for(int i=0;i<node_num;i++)
				node[i].svalue = 50 + (node[i].score - average) * 10 / std;
			
			
			minSvalue = node[0].svalue;
			maxSvalue = node[0].svalue;
			
			for(int i=1;i<node_num;i++)
			{
				if(node[i].svalue > maxSvalue)
					maxSvalue = node[i].svalue;
				if(node[i].svalue < minSvalue)
					minSvalue = node[i].svalue;
			}
			
			for(int i=0;i<node_num;i++)			
				node[i].y =  (int)(((node[i].svalue - map.minSvalue) / (map.maxSvalue - map.minSvalue)) * (sizeY - 100)) + 50;			
			
//			System.out.println("min , max svalues are "+minSvalue+" : "+maxSvalue);
			
		}	
	}
}
