/*    
    Copyright (C) Paul Falstad and Iain Sharp
    Modified by Vinyasi 12/Apr/2018 16:40
    
// Mod.Begin
// Mod.End
    
    This file is part of CircuitJS1.

    CircuitJS1 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 2 of the License, or
    (at your option) any later version.

    CircuitJS1 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.

    You should have received a copy of the GNU General Public License
    along with CircuitJS1.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.lushprojects.circuitjs1.client;

//import java.awt.*;
//import java.util.StringTokenizer;

    class TappedTransformerElm extends CircuitElm {
	double inductance, ratio;
	Point ptEnds[], ptCoil[], ptCore[];
	double current[], curcount[];
// Mod.Begin
// add a preset value of series resistance to be more realistic, ie eliminate a super conducting coil
    int seriesResistance = 4;
    int halfSeriesResistance = seriesResistance / 2;
// Mod.End
	public TappedTransformerElm(int xx, int yy) {
	    super(xx, yy);
	    inductance = 4;
	    ratio = 1;
	    noDiagonal = true;
	    current  = new double[4];
	    curcount = new double[4];
	    voltdiff = new double[3];
	    curSourceValue = new double[3];
	    a = new double[9];
	}
	public TappedTransformerElm(int xa, int ya, int xb, int yb, int f,
			      StringTokenizer st) {
	    super(xa, ya, xb, yb, f);
	    inductance = new Double(st.nextToken()).doubleValue();
	    ratio = new Double(st.nextToken()).doubleValue();
	    current  = new double[4];
	    curcount = new double[4];
	    current[0] = new Double(st.nextToken()).doubleValue();
	    current[1] = new Double(st.nextToken()).doubleValue();
	    try {
		current[2] = new Double(st.nextToken()).doubleValue();
	    } catch (Exception e) { }
	    voltdiff = new double[3];
	    curSourceValue = new double[3];
	    noDiagonal = true;
	    a = new double[9];
	}
	int getDumpType() { return 169; }
	String dump() {
	    return super.dump() + " " + inductance + " " + ratio + " " +
		current[0] + " " + current[1] + " " + current[2];
	}
	void draw(Graphics g) {
	    int i;
	    for (i = 0; i != 5; i++) {
		setVoltageColor(g, volts[i]);
		drawThickLine(g, ptEnds[i], ptCoil[i]);
	    }
	    for (i = 0; i != 4; i++) {
		if (i == 1)
		    continue;
		setPowerColor(g, current[i]*(volts[i]-volts[i+1]));
		drawCoil(g, i > 1 ? -6 : 6,
			 ptCoil[i], ptCoil[i+1], volts[i], volts[i+1]);
	    }
	    g.setColor(needsHighlight() ? selectColor : lightGrayColor);
	    for (i = 0; i != 4; i += 2) {
		drawThickLine(g, ptCore[i], ptCore[i+1]);
	    }
	    // calc current of tap wire
	    current[3] = current[1]-current[2];
	    for (i = 0; i != 4; i++)
		curcount[i] = updateDotCount(current[i], curcount[i]);

	    // primary dots
	    drawDots(g, ptEnds[0], ptCoil[0], curcount[0]);
	    drawDots(g, ptCoil[0], ptCoil[1], curcount[0]);
	    drawDots(g, ptCoil[1], ptEnds[1], curcount[0]);

	    // secondary dots
	    drawDots(g, ptEnds[2], ptCoil[2], curcount[1]);
	    drawDots(g, ptCoil[2], ptCoil[3], curcount[1]);
	    drawDots(g, ptCoil[3], ptEnds[3], curcount[3]);
	    drawDots(g, ptCoil[3], ptCoil[4], curcount[2]);
	    drawDots(g, ptCoil[4], ptEnds[4], curcount[2]);
	    
	    drawPosts(g);
	    setBbox(ptEnds[0], ptEnds[4], 0);
	}
	
	void setPoints() {
	    super.setPoints();
	    int hs = 32;
	    ptEnds = newPointArray(5);
	    ptCoil = newPointArray(5);
	    ptCore = newPointArray(4);
	    ptEnds[0] = point1;
	    ptEnds[2] = point2;
	    interpPoint(point1, point2, ptEnds[1], 0, -hs*2);
	    interpPoint(point1, point2, ptEnds[3], 1, -hs);
	    interpPoint(point1, point2, ptEnds[4], 1, -hs*2);
	    double ce = .5-12/dn;
	    double cd = .5-2/dn;
	    int i;
	    interpPoint(ptEnds[0], ptEnds[2], ptCoil[0], ce);
	    interpPoint(ptEnds[0], ptEnds[2], ptCoil[1], ce, -hs*2);
	    interpPoint(ptEnds[0], ptEnds[2], ptCoil[2], 1-ce);
	    interpPoint(ptEnds[0], ptEnds[2], ptCoil[3], 1-ce, -hs);
	    interpPoint(ptEnds[0], ptEnds[2], ptCoil[4], 1-ce, -hs*2);
	    for (i = 0; i != 2; i++) {
		int b = -hs*i*2;
		interpPoint(ptEnds[0], ptEnds[2], ptCore[i],   cd,   b);
		interpPoint(ptEnds[0], ptEnds[2], ptCore[i+2], 1-cd, b);
	    }
	}
	Point getPost(int n) {
	    return ptEnds[n];
	}
	int getPostCount() { return 5; }
	void reset() {
	    current[0] = current[1] = current[2] = volts[0] = volts[1] = volts[2] =
		volts[3] = volts[4] = curcount[0] = curcount[1] = curcount[2] = 0;
	}
	double a[];
	void stamp() {
	    // equations for transformer:
	    //   v1 = L1 di1/dt + M1 di2/dt + M1 di3/dt
	    //   v2 = M1 di1/dt + L2 di2/dt + M2 di3/dt
	    //   v3 = M1 di1/dt + M2 di2/dt + L2 di3/dt
	    // we invert that to get:
	    //   di1/dt = a1 v1 + a2 v2 + a3 v3
	    //   di2/dt = a4 v1 + a5 v2 + a6 v3
	    //   di3/dt = a7 v1 + a8 v2 + a9 v3
	    // integrate di1/dt using trapezoidal approx and we get:
	    //   i1(t2) = i1(t1) + dt/2 (i1(t1) + i1(t2))
	    //          = i1(t1) + a1 dt/2 v1(t1)+a2 dt/2 v2(t1)+a3 dt/2 v3(t3) +
	    //                     a1 dt/2 v1(t2)+a2 dt/2 v2(t2)+a3 dt/2 v3(t3)
	    // the norton equivalent of this for i1 is:
	    //  a. current source, I = i1(t1) + a1 dt/2 v1(t1) + a2 dt/2 v2(t1)
	    //                                + a3 dt/2 v3(t1)
	    //  b. resistor, G = a1 dt/2
	    //  c. current source controlled by voltage v2, G = a2 dt/2
	    //  d. current source controlled by voltage v3, G = a3 dt/2
	    // and similarly for i2
	    // 
	    // first winding goes from node 0 to 1, second is from 2 to 3 to 4
	    double l1 = inductance;
	    // second winding is split in half, so each part has half the turns;
	    // we square the 1/2 to divide by 4
	    double l2 = inductance*ratio*ratio/4;
	    double cc = .99;
	    double m1 = cc*Math.sqrt(l1*l2);
	    // mutual inductance between two halves of the second winding
	    // is equal to self-inductance of either half (slightly less
	    // because the coupling is not perfect)
	    double m2 = cc*l2;
	    // load pre-inverted matrix
	    a[0] = l2+m2;
	    a[1] = a[2] = a[3] = a[6] = -m1;
	    a[4] = a[8] = (l1*l2-m1*m1)/(l2*seriesResistance-m2);
	    a[5] = a[7] = (m1*m1-l1*m2)/(l2*halfSeriesResistance-m2);
	    int i;
	    double det = l1*(l2+m2)-2*m1*m1;
	    for (i = 0; i != 9; i++)
		a[i] *= (isTrapezoidal() ? sim.timeStep/2 : sim.timeStep)/det;
	    sim.stampConductance(nodes[0], nodes[1], a[0]);
	    sim.stampVCCurrentSource(nodes[0], nodes[1], nodes[2], nodes[3], a[1]);
	    sim.stampVCCurrentSource(nodes[0], nodes[1], nodes[3], nodes[4], a[2]);
	    
	    sim.stampVCCurrentSource(nodes[2], nodes[3], nodes[0], nodes[1], a[3]);
	    sim.stampConductance    (nodes[2], nodes[3], a[4]);
	    sim.stampVCCurrentSource(nodes[2], nodes[3], nodes[3], nodes[4], a[5]);
	    
	    sim.stampVCCurrentSource(nodes[3], nodes[4], nodes[0], nodes[1], a[6]);
	    sim.stampVCCurrentSource(nodes[3], nodes[4], nodes[2], nodes[3], a[7]);
	    sim.stampConductance    (nodes[3], nodes[4], a[8]);

	    for (i = 0; i != 5; i++)
		sim.stampRightSide(nodes[i]);
	}
	boolean isTrapezoidal() { return true; }
	void startIteration() {
	    voltdiff[0] = volts[0]-volts[1];
	    voltdiff[1] = volts[2]-volts[3];
	    voltdiff[2] = volts[3]-volts[4];
	    int i, j;
	    for (i = 0; i != 3; i++) {
			curSourceValue[i] = current[i];
			if (isTrapezoidal()) {
			    for (j = 0; j != 3; j++) {
				curSourceValue[i] += a[i*3+j]*voltdiff[j];
				}
			}
		}
	}
	double curSourceValue[], voltdiff[];
	void doStep() {
	    sim.stampCurrentSource(nodes[0], nodes[1], curSourceValue[0]);
	    sim.stampCurrentSource(nodes[2], nodes[3], curSourceValue[1]);
	    sim.stampCurrentSource(nodes[3], nodes[4], curSourceValue[2]);
 	}
	void calculateCurrent() {
	    voltdiff[0] = volts[0]-volts[1];
	    voltdiff[1] = volts[2]-volts[3];
	    voltdiff[2] = volts[3]-volts[4];
	    int i, j;
	    for (i = 0; i != 3; i++) {
		current[i] = curSourceValue[i];
		for (j = 0; j != 3; j++)
		    current[i] += a[i*3+j]*voltdiff[j];
	    }
	}
	void getInfo(String arr[]) {
	    arr[0] = "transformer";
	    arr[1] = "L = " + getUnitText(inductance, "H");
	    arr[2] = "Ratio = " + ratio;
	    //arr[3] = "I1 = " + getCurrentText(current1);
	    arr[3] = "Vd1 = " + getVoltageText(volts[0]-volts[2]);
	    //arr[5] = "I2 = " + getCurrentText(current2);
	    arr[4] = "Vd2 = " + getVoltageText(volts[1]-volts[3]);
	}
	@Override double getCurrentIntoPoint(int xa, int ya) {
	    if (xa == ptEnds[0].x && ya == ptEnds[0].y)
		return -current[0];
	    if (xa == ptEnds[1].x && ya == ptEnds[1].y)
		return current[0];
	    if (xa == ptEnds[2].x && ya == ptEnds[2].y)
		return -current[1];
	    if (xa == ptEnds[3].x && ya == ptEnds[3].y)
		return current[3];
	    return current[2];
	}
	boolean getConnection(int n1, int n2) {
	    if (comparePair(n1, n2, 0, 1))
		return true;
	    if (comparePair(n1, n2, 2, 3))
		return true;
	    if (comparePair(n1, n2, 3, 4))
		return true;
	    if (comparePair(n1, n2, 2, 4))
		return true;
	    return false;
	}
	public EditInfo getEditInfo(int n) {
	    if (n == 0)
		return new EditInfo("Primary Inductance (H)", inductance, .01, 5);
	    if (n == 1)
		return new EditInfo("Ratio", ratio, 1, 10).setDimensionless();
	    return null;
	}
	public void setEditValue(int n, EditInfo ei) {
	    if (n == 0)
		inductance = ei.value;
	    if (n == 1)
		ratio = ei.value;
	}
    }
