/*
 * JaamSim Discrete Event Simulation
 * Copyright (C) 2013 Ausenco Engineering Canada Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */
package com.jaamsim.DisplayModels;

import java.util.ArrayList;
import java.util.List;

import com.jaamsim.controllers.RenderManager;
import com.jaamsim.math.Color4d;
import com.jaamsim.math.Transform;
import com.jaamsim.math.Vec3d;
import com.jaamsim.math.Vec4d;
import com.jaamsim.render.DisplayModelBinding;
import com.jaamsim.render.HasScreenPoints;
import com.jaamsim.render.LineProxy;
import com.jaamsim.render.PointProxy;
import com.jaamsim.render.RenderProxy;
import com.jaamsim.render.RenderUtils;
import com.sandwell.JavaSimulation.ChangeWatcher;
import com.sandwell.JavaSimulation.ColourInput;
import com.sandwell.JavaSimulation.Entity;
import com.sandwell.JavaSimulation3D.DisplayEntity;

public class ScreenPointsModel extends DisplayModel {

	private static final Color4d MINT = ColourInput.getColorWithName("mint");

	@Override
	public DisplayModelBinding getBinding(Entity ent) {
		return new Binding(ent, this);
	}

	@Override
	public boolean canDisplayEntity(Entity ent) {
		return (ent instanceof HasScreenPoints) && (ent instanceof DisplayEntity);
	}

	protected class Binding extends DisplayModelBinding {

		//private Segment _segmentObservee;
		protected HasScreenPoints screenPointObservee;
		protected DisplayEntity displayObservee;
		private ChangeWatcher.Tracker observeeTracker;
		private ChangeWatcher.Tracker dmTracker;

		protected ArrayList<Vec4d> selectionPoints = null;
		private ArrayList<Vec4d> nodePoints = null;
		private LineProxy[] cachedProxies = null;

		public Binding(Entity ent, DisplayModel dm) {
			super(ent, dm);

			try {
				screenPointObservee = (HasScreenPoints)ent;
				displayObservee = (DisplayEntity)ent;
				if (displayObservee != null) {
					observeeTracker = displayObservee.getGraphicsChangeTracker();
				}
			} catch (ClassCastException e) {
				// The observee is not a display entity
				screenPointObservee = null;
				displayObservee = null;
			}
			dmTracker = dm.getGraphicsChangeTracker();

		}

		/**
		 * Update the cached Points list
		 */
		protected void updateProxies(double simTime) {

			if (cachedProxies != null && observeeTracker != null && !observeeTracker.checkAndClear()
			    && !dmTracker.checkAndClear()) {
				// up to date
				_cacheHits++;
				return;
			}

			_cacheMisses++;
			registerCacheMiss("Points");

			HasScreenPoints.PointsInfo[] pis = screenPointObservee.getScreenPoints();

			if (pis.length == 0) {
				cachedProxies = new LineProxy[0];
				return;
			}

			selectionPoints = new ArrayList<Vec4d>();
			nodePoints = new ArrayList<Vec4d>();

			// Cache the points in the first series for selection and editing
			ArrayList<Vec3d> basePoints = pis[0].points;
			if (basePoints == null || basePoints.size() < 2) {
				cachedProxies = new LineProxy[0];
				return;
			}

			for (int i = 1; i < basePoints.size(); ++i) { // Skip the first point
				Vec3d start = basePoints.get(i - 1);
				Vec3d end = basePoints.get(i);

				selectionPoints.add(new Vec4d(start.x, start.y, start.z, 1.0d));
				selectionPoints.add(new Vec4d(end.x, end.y, end.z, 1.0d));
			}

			for (int i = 0; i < basePoints.size(); ++i) {
				// Save the point list as is for control nodes
				Vec3d p = basePoints.get(i);
				nodePoints.add(new Vec4d(p.x, p.y, p.z, 1.0d));
			}

			Transform regionTrans = null;
			if (displayObservee.getCurrentRegion() != null) {
				regionTrans = displayObservee.getCurrentRegion().getRegionTrans(simTime);
				RenderUtils.transformPointsLocal(regionTrans, selectionPoints, 0);
				RenderUtils.transformPointsLocal(regionTrans, nodePoints, 0);
			}

			// Add the line proxies
			cachedProxies = new LineProxy[pis.length];

			int proxyIndex = 0;
			for (HasScreenPoints.PointsInfo pi : pis) {
				List<Vec4d> points = new ArrayList<Vec4d>();

				for (int i = 1; i < pi.points.size(); ++i) { // Skip the first point
					Vec3d start = pi.points.get(i - 1);
					Vec3d end = pi.points.get(i);

					points.add(new Vec4d(start.x, start.y, start.z, 1.0d));
					points.add(new Vec4d(end.x, end.y, end.z, 1.0d));
				}

				if (regionTrans != null) {
					RenderUtils.transformPointsLocal(regionTrans, points, 0);
				}

				cachedProxies[proxyIndex++] = new LineProxy(points, pi.color, pi.width, getVisibilityInfo(), displayObservee.getEntityNumber());
			}
		}

		@Override
		public void collectProxies(double simTime, ArrayList<RenderProxy> out) {

			if (displayObservee == null || screenPointObservee == null ||!displayObservee.getShow()) {
				return;
			}

			updateProxies(simTime);

			if (cachedProxies == null) {
				int i = 0;
			}
			for (LineProxy lp : cachedProxies) {
				out.add(lp);
			}
		}

		@Override
		public void collectSelectionProxies(double simTime, ArrayList<RenderProxy> out) {

			if (displayObservee == null ||
			    screenPointObservee == null ||
			    !displayObservee.getShow() ||
			    !screenPointObservee.selectable()) {
				return;
			}

			updateProxies(simTime);

			if (selectionPoints.size() == 0) {
				return;
			}

			LineProxy lp = new LineProxy(selectionPoints, MINT, 2, getVisibilityInfo(), RenderManager.LINEDRAG_PICK_ID);
			lp.setHoverColour(ColourInput.LIGHT_GREY);
			out.add(lp);

			for (int i = 0; i < nodePoints.size(); ++i) {
				List<Vec4d> pl = new ArrayList<Vec4d>(1);

				pl.add(new Vec4d(nodePoints.get(i)));
				PointProxy pp = new PointProxy(pl, ColourInput.GREEN, 8, getVisibilityInfo(), RenderManager.LINENODE_PICK_ID - i);
				pp.setHoverColour(ColourInput.LIGHT_GREY);
				out.add(pp);
			}

		}

	}
}

@@ -5099,60 +5099,8 @@
 );%0A%0A
-%09%09%09if (cachedProxies == null) %7B%0A%09%09%09%09int i = 0;%0A%09%09%09%7D%0A
 %09%09%09f

kill a leftover if block