import java.awt.*;

public class VColumn extends HVectorColumn {
	// const fields
	final static int	defaultLevels = 100;

	// configuration parameters
	int		levels;
	int		impulseLength = 10;
	double		fTimeStep = 0.01;
			// (f * TIME_STEP)
	double		nuTimeStep = 0.2;
			// (nu * TIME_STEP / VERTICAL_STEP ** 2)
	volatile boolean	followRotation = true;
	volatile boolean	indicialFlag = false;
	volatile boolean	stressFlag = false;

	volatile int		impulse = 0;
	volatile boolean	resized = false;
	Transpose3d		t3;
	VColumnConfigDialog	dlg;

	VColumn() {
		super(defaultLevels);
		levels = defaultLevels;
		t3 = new Transpose3d();
	}

	public HVectorColumn trend() {
		HVectorColumn  deflection, diffusion;

		// Coriolis force
		deflection = new HVectorColumn(this);
		deflection.rot(HVector.R90);
		deflection.mul(fTimeStep);

		// diffusion term
		diffusion = new HVectorColumn(this);
		diffusion.laplace();
		diffusion.mul(nuTimeStep);
		deflection.add(diffusion);

		// boundary value is fixed, so no trend is calculated
		if (!stressFlag)
			deflection.column[0].clear();
		deflection.column[column.length - 1].clear();
		return deflection;
	}

	public void paint(Graphics g) {
		// give boundary grid value if not stress mode
		if (!stressFlag) {
			if (impulse > 0)
				column[0].set(1.0, 0.0);
			else
				column[0].clear();
		}
		if (!indicialFlag && (impulse > 0))
			impulse--;
		if (needResize())
			super.resize(levels);
		t3.drawScale(g);
		g.setColor(Color.red);
		super.paint(g, t3);
		add(trend());
		if (followRotation)
			t3.rotate(-fTimeStep);
	}
	public void rotateView(boolean b) { followRotation = b; }
	public void stressForcing(boolean b) { stressFlag = b; }

	public void impulse() {
		if (stressFlag)
			column[0].set(1.0, 0.0);
		if (impulse > 0) {
			impulse = 0;
		} else {
			impulse = impulseLength;
		}
	}
	public void indicial(boolean b) { indicialFlag = b; }

	public void reconfig() {
		if (dlg != null) return;
		dlg = new VColumnConfigDialog("configuration", this);
	}

	public void reconfigDone() { dlg = null; }

	public boolean needResize() {
		boolean	tmp = resized;
		resized = false;
		return tmp;
	}

	public void setElevation(double lambda_given) {
		t3.lambda = lambda_given / 180.0 * Math.PI;
	}
}


class VColumnConfigDialog extends Frame {
	final int	digits = 10;
	final int	dlgItems = 6, dlgWidth = 250, dlgHeight = 150;
	TextField	impLen, levels, timeStep, diffusion, lambda;
	VColumn		vc = null;

	VColumnConfigDialog(String title, VColumn vc) {
		super(title);
		this.vc = vc;

		setLayout(new GridLayout(dlgItems, 2));

		levels = addTextField("levels");
		impLen = addTextField("impulse length");
		timeStep = addTextField("dt * f");
		diffusion = addTextField("nu * dt / (dz^2)");
		lambda = addTextField("lambda [degree]");
		initTextFields();

		add(new Button("OK"));
		add(new Button("CANCEL"));

		resize(dlgWidth, dlgHeight);
		show();
	}

	private TextField addTextField(String title) {
		add(new Label(title));
		TextField tmp = new TextField(digits);
		add(tmp);
		return tmp;
	}

	private void initTextFields() {
		levels.setText(String.valueOf(vc.levels));
		impLen.setText(String.valueOf(vc.impulseLength));
		timeStep.setText(String.valueOf(vc.fTimeStep));
		diffusion.setText(String.valueOf(vc.nuTimeStep));
		lambda.setText(String.valueOf(vc.t3.lambda * 180.0 / Math.PI));
	}

	public boolean action(Event evt, Object arg) {
		if (evt.target instanceof Button) {
			if (arg.toString().equals("OK")) {
				if (!setVcc()) return true;
			}
			endDialog();
		} else {
			return false;
		}
		return true;
	}

	public void endDialog() {
		dispose();
		vc.reconfigDone();
	}

	public boolean setVcc() {
		int	lev, iL;
		double	fTS, nTS, lam;
		try {
			iL = Integer.valueOf(impLen.getText()).intValue();
			lev = Integer.valueOf(levels.getText()).intValue();
			fTS = Double.valueOf(timeStep.getText()).doubleValue();
			nTS = Double.valueOf(diffusion.getText()).doubleValue();
			lam = Double.valueOf(lambda.getText()).doubleValue();
		} catch (NumberFormatException e) {
			initTextFields();
			return false;
		}
		vc.resized = (vc.levels != lev);
		vc.impulseLength = iL;
		vc.levels = lev;
		vc.fTimeStep = fTS;
		vc.nuTimeStep = nTS;
		vc.t3.lambda = lam * Math.PI / 180.0;
		return true;
	}
}
