/*
    Copyright (C) Paul Falstad and Iain Sharp
    Modified by Vinyasi on 12/Apr/2018 16:58

// 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;

    class CapacitorElm extends CircuitElm {
	double capacitance;
	double compResistance, voltdiff;
	Point plate1[], plate2[];
	public static final int FLAG_BACK_EULER = 2;
// Mod.Begin
// add a preset value of series resistance to be more realistic, ie eliminate a super conducting capacitor
    int seriesResistance = 1000;
// Mod.End
	public CapacitorElm(int xx, int yy) {
	    super(xx, yy);
	    capacitance = 1e-5;
	}
	public CapacitorElm(int xa, int ya, int xb, int yb, int f,
			    StringTokenizer st) {
	    super(xa, ya, xb, yb, f);
	    capacitance = new Double(st.nextToken()).doubleValue();
	    voltdiff = new Double(st.nextToken()).doubleValue();
	}
	boolean isTrapezoidal() { return (flags & FLAG_BACK_EULER) == 0; }
	void setNodeVoltage(int n, double c) {
	    super.setNodeVoltage(n, c);
	    voltdiff = volts[0]-volts[1];
	}
	void reset() {
	    super.reset();
	    current = curcount = curSourceValue = 0;
	    // put small charge on caps when reset to start oscillators
// Mod.Begin
//	    voltdiff = 1e-3; // this is very inconvenient for me ...
	    voltdiff = 0;
// Mod.End
	}
	int getDumpType() { return 'c'; }
	String dump() {
	    return super.dump() + " " + capacitance + " " + voltdiff;
	}
	
	Point platePoints[];
	
	void setPoints() {
	    super.setPoints();
	    double f = (dn/2-4)/dn;
	    // calc leads
	    lead1 = interpPoint(point1, point2, f);
	    lead2 = interpPoint(point1, point2, 1-f);
	    // calc plates
	    plate1 = newPointArray(2);
	    plate2 = newPointArray(2);
	    interpPoint2(point1, point2, plate1[0], plate1[1], f, 12);
	    interpPoint2(point1, point2, plate2[0], plate2[1], 1-f, 12);
	}
	
	void draw(Graphics g) {
	    int hs = 12;
	    setBbox(point1, point2, hs);
	    
	    // draw first lead and plate
	    setVoltageColor(g, volts[0]);
	    drawThickLine(g, point1, lead1);
	    setPowerColor(g, false);
	    drawThickLine(g, plate1[0], plate1[1]);
	    if (sim.powerCheckItem.getState())
		g.setColor(Color.gray);

	    // draw second lead and plate
	    setVoltageColor(g, volts[1]);
	    drawThickLine(g, point2, lead2);
	    setPowerColor(g, false);
	    if (platePoints == null)
		drawThickLine(g, plate2[0], plate2[1]);
	    else {
		int i;
		for (i = 0; i != 7; i++)
		    drawThickLine(g,  platePoints[i], platePoints[i+1]);
	    }
	    
	    updateDotCount();
	    if (sim.dragElm != this) {
		drawDots(g, point1, lead1, curcount);
		drawDots(g, point2, lead2, -curcount);
	    }
	    drawPosts(g);
	    if (sim.showValuesCheckItem.getState()) {
		String s = getShortUnitText(capacitance, "F");
		drawValues(g, s, hs);
	    }
	}
	void stamp() {
	    // capacitor companion model using trapezoidal approximation
	    // (Norton equivalent) consists of a current source in
	    // parallel with a resistor.  Trapezoidal is more accurate
	    // than backward euler but can cause oscillatory behavior
	    // if RC is small relative to the timestep.
// Mod.Begin
//	    if (isTrapezoidal())
//		compResistance = sim.timeStep/(2*capacitance);
//	    else
//		compResistance = sim.timeStep/capacitance;
	    if (isTrapezoidal())
		compResistance = sim.timeStep/(2*capacitance*seriesResistance);
	    else
		compResistance = sim.timeStep/(capacitance*seriesResistance);
// Mod.End
	    sim.stampResistor(nodes[0], nodes[1], compResistance);
	    sim.stampRightSide(nodes[0]);
	    sim.stampRightSide(nodes[1]);
	}
	void startIteration() {
	    if (isTrapezoidal())
		curSourceValue = -voltdiff/compResistance-current;
	    else
		curSourceValue = -voltdiff/compResistance;
	}
	void calculateCurrent() {
	    double voltdiff = volts[0] - volts[1];
	    // we check compResistance because this might get called
	    // before stamp(), which sets compResistance, causing
	    // infinite current
	    if (compResistance > 0)
		current = voltdiff/compResistance + curSourceValue;
	}
	double curSourceValue;
	void doStep() {
	    sim.stampCurrentSource(nodes[0], nodes[1], curSourceValue);
 	}
	void getInfo(String arr[]) {
	    arr[0] = "capacitor";
	    getBasicInfo(arr);
	    arr[3] = "C = " + getUnitText(capacitance, "F");
	    arr[4] = "P = " + getUnitText(getPower(), "W");
	    //double v = getVoltageDiff();
	    //arr[4] = "U = " + getUnitText(.5*capacitance*v*v, "J");
	}
	@Override
	String getScopeText(int v) {
	    return sim.LS("capacitor") + ", " + getUnitText(capacitance, "F");
	}
	public EditInfo getEditInfo(int n) {
	    if (n == 0)
		return new EditInfo("Capacitance (F)", capacitance, 0, 0);
	    if (n == 1) {
		EditInfo ei = new EditInfo("", 0, -1, -1);
		ei.checkbox = new Checkbox("Trapezoidal Approximation", isTrapezoidal());
		return ei;
	    }
	    return null;
	}
	public void setEditValue(int n, EditInfo ei) {
	    if (n == 0 && ei.value > 0)
		capacitance = ei.value;
	    if (n == 1) {
		if (ei.checkbox.getState())
		    flags &= ~FLAG_BACK_EULER;
		else
		    flags |= FLAG_BACK_EULER;
	    }
	}
	int getShortcut() { return 'c'; }
    }
