package cuckoohashing;


import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableColorProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.part.ViewPart;

import cuckoomodel.Interval;
import cuckoomodel.Network;
import cuckoomodel.Network.Attack;

public class View extends ViewPart {
	private Label roundsLabel;
	public static final String ID = "CuckooHashing.view";

	private TableViewer viewer;


	private Network network = new Network();



	/**
	 * This is a callback that will allow us to create the viewer and initialize
	 * it.
	 */
	public void createPartControl(Composite parent) {
		parent.setLayout(new FillLayout());
		final SashForm sashForm = new SashForm(parent, SWT.NONE);
		Composite comp = new Composite(sashForm ,SWT.NONE);
		final GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 2;
		comp.setLayout(gridLayout);

		final Spinner spinner = new Spinner(comp, SWT.BORDER);
		spinner.setSelection(26);
		spinner.setMaximum(10000);

		final Label numberOfIntervalsLabel = new Label(comp, SWT.NONE);
		numberOfIntervalsLabel.setText("Number of Intervals (n/k)");

		final Button createButton = new Button(comp, SWT.NONE);
		createButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				network.init(spinner.getSelection());
				viewer.refresh();
			}
		});
		createButton.setText("Create");
		new Label(comp, SWT.NONE);

		final Group joinGroup = new Group(comp, SWT.NONE);
		final GridLayout gridLayout_1 = new GridLayout();
		gridLayout_1.numColumns = 2;
		joinGroup.setLayout(gridLayout_1);
		joinGroup.setText("Join");
		joinGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));

		final Button evilButton = new Button(joinGroup, SWT.RADIO);
		evilButton.setText("Evil");

		final Button goodButton = new Button(joinGroup, SWT.RADIO);
		goodButton.setSelection(true);
		goodButton.setText("Good");

		final Spinner spinner_1 = new Spinner(joinGroup, SWT.BORDER);
		spinner_1.setSelection(10);
		spinner_1.setMaximum(10000);

		final Label peersLabel = new Label(joinGroup, SWT.NONE);
		peersLabel.setText("Peers");

		final Button joinButton = new Button(joinGroup, SWT.NONE);
		joinButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				network.addPeers(spinner_1.getSelection(), evilButton.getSelection());
				viewer.refresh();
			}
		});
		joinButton.setText("Join");
		new Label(joinGroup, SWT.NONE);

		final Group rejoinAttackGroup = new Group(comp, SWT.NONE);
		rejoinAttackGroup.setText("Rejoin Attack");
		rejoinAttackGroup.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
		final GridLayout gridLayout_2 = new GridLayout();
		gridLayout_2.numColumns = 2;
		rejoinAttackGroup.setLayout(gridLayout_2);

		final Spinner spinner_1_1 = new Spinner(rejoinAttackGroup, SWT.BORDER);
		spinner_1_1.setSelection(5);
		spinner_1_1.setMaximum(10000);

		final Label peersLabel_1 = new Label(rejoinAttackGroup, SWT.NONE);
		peersLabel_1.setLayoutData(new GridData());
		peersLabel_1.setText("Evil Peers");

		final Spinner spinner_3 = new Spinner(rejoinAttackGroup, SWT.BORDER);
		spinner_3.setSelection(5);
		spinner_3.setMaximum(10000);

		final Label regionsToConquerLabel = new Label(rejoinAttackGroup, SWT.NONE);
		regionsToConquerLabel.setText("Regions to Conquer");

		final Spinner spinner_2 = new Spinner(rejoinAttackGroup, SWT.BORDER);
		spinner_2.setSelection(10);
		spinner_2.setMaximum(10000);

		final Label showEveryXLabel = new Label(rejoinAttackGroup, SWT.NONE);
		showEveryXLabel.setText("Show every X Rounds");

		final Button joinButton_1 = new Button(rejoinAttackGroup, SWT.NONE);
		joinButton_1.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(final SelectionEvent e) {
				final int attackers= spinner_1_1.getSelection();
				final int regions = spinner_3.getSelection();
				final int showEveryXRounds = spinner_2.getSelection();
				new Thread(new Runnable() {
					public void run() {
						rejoinAttack(attackers, regions, showEveryXRounds);
					}
				}).start();
			}
		});
		joinButton_1.setText("Attack");

		roundsLabel = new Label(rejoinAttackGroup, SWT.NONE);
		roundsLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
		
		viewer = new TableViewer(sashForm , SWT.MULTI | SWT.H_SCROLL
				| SWT.V_SCROLL| SWT.FULL_SELECTION);
		

		viewer.getTable().setHeaderVisible(true);
		viewer.getTable().setLinesVisible(true);
		
		addColumn("Total");
		addColumn("Good");
		addColumn("Malicious");
		
		viewer.setLabelProvider(new TableLabelProvider());
		
		viewer.setContentProvider(new ContentProvider());
		
		viewer.setInput(network);
	}
	
	private void rejoinAttack(int attackers,int regionsToConquer,int showEveryXRounds) {
		Attack att= network.rejoinAttack(attackers, regionsToConquer);
		int round = 0;
		
		
		while (!att.attack()) {
			round++;
			if (round % showEveryXRounds == 0) {
				final int currentRounds = round; 
				Display.getDefault().syncExec(new Runnable() {
					@Override
					public void run() {
						roundsLabel.setText(currentRounds+" Rounds");
						viewer.refresh();
					}
				});
				try {
					Thread.sleep(1000);
				} catch(InterruptedException ie) {}
				
			}
		}
		
		final int currentRounds = round; 
		Display.getDefault().syncExec(new Runnable() {
			@Override
			public void run() {
				roundsLabel.setText(currentRounds+" Rounds");
				viewer.refresh();
			}
		});
		
	}
	
	
	
	private void addColumn(String title) {
		TableColumn col = new TableColumn(viewer.getTable(),SWT.NONE);
		col.setText(title);
		col.setWidth(80);
	}

	/**
	 * Passing the focus request to the viewer's control.
	 */
	public void setFocus() {
		viewer.getControl().setFocus();
	}
	
	
	class TableLabelProvider implements ITableLabelProvider,ITableColorProvider {


		@Override
		public void addListener(ILabelProviderListener listener) {}

		@Override
		public void dispose() {}


		@Override
		public boolean isLabelProperty(Object element, String property) {
			return false;
		}


		@Override
		public void removeListener(ILabelProviderListener listener) {}


		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
		 */
		@Override
		public String getColumnText(Object element, int columnIndex) {
			Interval inter = (Interval)element;
			switch(columnIndex) {
			case 0: return Integer.toString(inter.getNumberOfPeers());
			case 1: return Integer.toString(inter.getGoodPeers());
			case 2: return Integer.toString(inter.getEvilPeers());
			}
			throw new IllegalStateException("unreachable");
		}

		/* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ITableColorProvider#getBackground(java.lang.Object, int)
		 */
		@Override
		public Color getBackground(Object element, int columnIndex) {
			Interval inter = (Interval)element;
			if (columnIndex == 0) {
				return Display.getDefault().getSystemColor(
						inter.isCompromised()? SWT.COLOR_DARK_RED: SWT.COLOR_BLUE);
			}
			return null;
		}

		/* (non-Javadoc)
		 * @see org.eclipse.jface.viewers.ITableColorProvider#getForeground(java.lang.Object, int)
		 */
		@Override
		public Color getForeground(Object element, int columnIndex) {
			if (columnIndex > 0) {
				return Display.getDefault().getSystemColor(
						columnIndex== 2 ? SWT.COLOR_DARK_RED: SWT.COLOR_BLUE);
			}
			return null;
		}
	}
	
	class ContentProvider implements IStructuredContentProvider {

		@Override
		public Object[] getElements(Object inputElement) {
			return network.getIntervals().toArray();
		}

		@Override
		public void dispose() {}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
		
	}
	protected Label getRoundsLabel() {
		return roundsLabel;
	}
	
}