package kr.util;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

/**
 * Handles notification of errors, progress, and other things. Makes sure only one notification is shown at a time
 */
public class NotificationManager {
	private static NotificationManager it = new NotificationManager();
	
	private static enum State { NOTHING, DISPLAY_PROGRESS };
	
	private State state = State.NOTHING;

	private JProgressBar bar;

	private JLabel statusLabel;
	
	private boolean useGui = true;

	private List<MultiSegmentTask> multiSegmentQueue = new ArrayList<MultiSegmentTask>(); 
	
	class MultiSegmentTask
	{
		int subTasks;
		int subTasksCompleted;
		String name;
		
		public MultiSegmentTask(String name, int subTasks)
		{
			this.name = name;
			this.subTasks = subTasks;
		}

		public double updateValue(double value) {
			if(value == -1)
				value = 0;
			
			return value / subTasks + ((double)subTasksCompleted / subTasks);
		}

		public void finishTask() {
			subTasksCompleted++;
			progress(0, "");
		}
	}
	
	public NotificationManager()
	{
	}
	
	public static NotificationManager inst()
	{
		return it;
	}
	
	/**
	 * Start a task with several sub tasks in it
	 */
	public void startMultiSegment(String name, int subTasks)
	{
		multiSegmentQueue.add(new MultiSegmentTask(name, subTasks));
	}
	
	/**
	 * Finish a task with several sub tasks in it
	 */
	public void finishMultiSegment(String name)
	{
		while(multiSegmentQueue.size() > 0)
		{
			if(multiSegmentQueue.get(multiSegmentQueue.size()-1).name.equals(name))
			{
				break;
			}
			multiSegmentQueue.remove(multiSegmentQueue.size()-1);
		}
		
		multiSegmentQueue.remove(multiSegmentQueue.size()-1);

		if(multiSegmentQueue.size() == 0) unfreezeUI();
		else multiSegmentQueue.get(multiSegmentQueue.size()-1).finishTask();
	}
	
	public void progress(double value, String desc)
	{
		for(int i = multiSegmentQueue.size()-1; i >= 0; i--)
		{
			value = multiSegmentQueue.get(i).updateValue(value);
			if(!desc.equals(""))
				desc = multiSegmentQueue.get(i).name+": "+desc;
			else
				desc = multiSegmentQueue.get(i).name;
		}
		
		if(bar != null)
		{
			if(state == State.NOTHING)
			{
				bar.setVisible(true);
				bar.getTopLevelAncestor().setCursor(Cursor.getPredefinedCursor(
						Cursor.WAIT_CURSOR )); //TODO: doesn't work because we disable the window, how to fix this???
				bar.getTopLevelAncestor().setEnabled(false);
			}
			
			if(value == -1)
			{
				bar.setIndeterminate(true);
				bar.setStringPainted(false);
			}
			else
			{
				bar.setIndeterminate(false);
				bar.setValue((int) Math.round(value * 1000));
				bar.setStringPainted(true);
			}
		}
		if(statusLabel != null)
			statusLabel.setText(desc);
		
		state = State.DISPLAY_PROGRESS;
	}
	
	public void finish()
	{
		if(multiSegmentQueue.size() > 0)
		{
			multiSegmentQueue.get(multiSegmentQueue.size()-1).finishTask();
			//if there is a multi segment task, then we wait for it to finish before unfreezing the ui
		}
		else
			unfreezeUI();
	}
	
	private void unfreezeUI()
	{	
		state = State.NOTHING;
		if(bar != null)
		{
			bar.setVisible(false);
			bar.getTopLevelAncestor().setEnabled(true);
			bar.getTopLevelAncestor().setCursor(Cursor.getPredefinedCursor(
					Cursor.DEFAULT_CURSOR ) );
		}
		if(statusLabel != null) {
			statusLabel.setText(" ");
		}
	}
	
	public void error(String desc)
	{
		multiSegmentQueue.clear();
		unfreezeUI();
		
		Component c;
		if(bar != null) c = bar;
		else if(statusLabel != null)
			c = statusLabel;
		else
			return;
			
		JOptionPane.showMessageDialog(c, new JLabel(desc), "Error", JOptionPane.ERROR_MESSAGE);
	}	
	
	public void setProgressBar(JProgressBar bar) {
		useGui = true;
		this.bar = bar;
		bar.setMinimum(0);
		bar.setMaximum(1000);
		bar.setVisible(false);
	}
	
	public void setStatusLabel(JLabel l) {
		useGui = true;
		this.statusLabel = l;
	}

//	public static class ProgressBarPanel extends JPanel
//	{
//		private JProgressBar bar;
//		private JLabel label;
//
//		ProgressBarPanel()
//		{
//			init();
//		}
//		
//		private void init()
//		{
//			setLayout(new GridBagLayout());
//
//	        GridBagConstraints c = new GridBagConstraints();
//	        c.weightx = c.weighty = 1;
//	        c.fill = c.BOTH;
//	        c.gridx=c.gridy=0;
//	        c.gridwidth=c.gridheight=1;
//	       
//	        add(bar = new JProgressBar(),c);
//	        bar.setMinimum(0);
//	        bar.setMaximum(1000);
//	        
//	        c.gridy++;
//	        c.weighty=0;
//	        
//	        add(label = new JLabel(),c);
//
//	        
//		}
//		
//		public void setValue(double value)
//		{
//			bar.setIndeterminate(value == -1);
//			bar.setValue((int) Math.round(value * 1000));
//			bar.setStringPainted(true);
//			//System.out.println("setting value to "+(value * 1000));
//			//repaint();
//		}
//		
//		public void setLabel(String text)
//		{
//			label.setText(text);
//			//repaint();
//		}
//	}

}

class NotificationManagerTest
{
	public static void main( String [] argv) throws Exception
	{
		NotificationManager nm = NotificationManager.inst();
		
		nm.startMultiSegment("multiseg", 3);
		
		for(int k = 0; k < 3; k++)
		{
			for(double i = 0; i <= 1; i+= .001)
			{
				nm.progress(i, "test");
				Thread.sleep(10);
			}
			nm.finish();
			Thread.sleep(1000);			
		}
	}
}
