//Name: Utflow.java
//Version: 1.3 
//Created by: Ferdi Hellweger
//            Center for Resarch in Water Resources
//            The University of Texas at Austin
//            ferdi@crwr.utexas.edu
//Created on: 03/21/97
//Description: This applet computes the EGL and HGL for
//a simple linear pipe system.
//
//-------------------------
//-------------------------
//--- import some stuff ---
//-------------------------
//-------------------------
//
import java.awt.*;
import java.awt.image.*;
import java.applet.*;
import java.lang.*;
//
//-------------------------------
//-------------------------------
//--- applet class definition ---
//-------------------------------
//-------------------------------
//
public class Utflow extends Applet {
    //
    //-------------------------
    //--- declare variables ---
    //-------------------------
    //
    Label lh, ld1, ld2, ld3, ld4;
    Label lc1, lc2, lc3, lc4;
    TextField fc1, fc2, fc3, fc4;
    Panel input, head;
    double d1, d2, d3, d4;
    double cptotal, cmtotal, hptotal, httotal, q, deglmax, deglmin, dhglmax, dhglmin;
    Double D1, D2, D3, D4;
    String s1, s2, s3, s4;
    int llevel, rlevel, fd, eglmax, eglmin, hglmax, hglmin;
    double ellevel, erlevel;
    int i, j, k, m, n;
    int curtype;
    App app[], newtoapp, curapp, newapp, thisapp, lastapp;
    Pipe pipe[], curpipe, thispipe, lastpipe, newpipe;
    Map map;
    boolean eof;
    //
    //---------------------------
    //--- initiate the applet ---
    //---------------------------
    //
    public void init() {
        //
        //--- main display ---
        //
        setBackground(Color.lightGray);
        setLayout(new BorderLayout(10, 10));
        input = new Panel();
        add("South", input);
        input.setLayout(new GridLayout(3, 4, 10, 10));
        lh = new Label("UTFLOW V1.3", Label.LEFT);
        add("North", lh);
        lc1 = new Label("", Label.RIGHT);
        lc2 = new Label("", Label.RIGHT);
        lc3 = new Label("", Label.RIGHT);
        lc4 = new Label("", Label.RIGHT);
        fc1 = new TextField("", 5);
        fc2 = new TextField("", 5);
        fc3 = new TextField("", 5);
        fc4 = new TextField("", 5);
        input.add(lc1);
        input.add(fc1);
        input.add(lc2);
        input.add(fc2);
        input.add(lc3);
        input.add(fc3);
        input.add(lc4);
        input.add(fc4);
        ld1 = new Label("", Label.RIGHT);
        ld2 = new Label("", Label.RIGHT);
        ld3 = new Label("", Label.RIGHT);
        ld4 = new Label("", Label.RIGHT);
        input.add(ld1);
        input.add(ld2);
        input.add(ld3);
        input.add(ld4);
        //
        //--- map ---
        //
        map = new Map();
        map.Utflow = this;
        map.mode = 0;
        map.setBackground(Color.lightGray);
        add("Center", map);
        map.init();
        //
        //--- default data ---
        //
        //reservoir levels
        //
        llevel = 50;
        rlevel = 100;
        //
        //apps
        //
        app = new App[6];
        //
        app[1] = new App();
        app[1].type = "joint";
        app[1].k = 0.5;
        app[1].x = 150;
        //
        app[2] = new App();
        app[2].type = "joint";
        app[2].k = 0.5;
        app[2].x = 250;
        //
        app[3] = new App();
        app[3].type = "pump";
        app[3].x = 300;
        app[3].hp = 10;
        //
        app[4] = new App();
        app[4].type = "joint";
        app[4].k = 0.5;
        app[4].x = 350;
        //
        app[5] = new App();
        app[5].type = "joint";
        app[5].k = 0.5;
        app[5].x = 450;
        //
        //pipes
        //
        pipe = new Pipe[5];
        //
        pipe[1] = new Pipe();
        pipe[1].length = 30;
        pipe[1].diameter = 0.20;
        pipe[1].friction = 0.025;
        pipe[1].fromapp = app[1];
        pipe[1].toapp = app[2];
        pipe[1].calculate();
        //
        pipe[2] = new Pipe();
        pipe[2].length = 20;
        pipe[2].diameter = 0.10;
        pipe[2].friction = 0.025;
        pipe[2].fromapp = app[2];
        pipe[2].toapp = app[3];
        pipe[2].calculate();
        //
        pipe[3] = new Pipe();
        pipe[3].length = 30;
        pipe[3].diameter = 0.20;
        pipe[3].friction = 0.025;
        pipe[3].fromapp = app[3];
        pipe[3].toapp = app[4];
        pipe[3].calculate();
        //
        pipe[4] = new Pipe();
        pipe[4].length = 30;
        pipe[4].diameter = 0.20;
        pipe[4].friction = 0.025;
        pipe[4].fromapp = app[4];
        pipe[4].toapp = app[5];
        pipe[4].calculate();
        //
        app[1].topipe = pipe[1];
        app[2].frompipe = pipe[1];
        app[2].topipe = pipe[2];
        app[3].frompipe = pipe[2];
        app[3].topipe = pipe[3];
        app[4].frompipe = pipe[3];
        app[4].topipe = pipe[4];
        app[5].frompipe = pipe[4];
        //
        app[1].calculate();
        app[2].calculate();
        app[3].calculate();
        app[4].calculate();
        app[5].calculate();
        //
        //current
        //
        //curtype
        //1 = pipe
        //2 = app
        //
        curtype = 1;
        curpipe = pipe[2];
        //
        //--- initiate edit area ---
        //
        updateedit();
        //
        //--- calculate ---
        //
        calculate();
        //
        //--- repaint ---
        //
        map.offx = 0;
        map.offy = 0;
        map.clipw = 600;
        map.cliph = 300;
        map.repaint();
    }
    //
    //--------------
    //--- action ---
    //--------------
    //
    public boolean action(Event evt, Object arg) {
        apply();
        calculate();
        map.offx = 0;
        map.offy = 0;
        map.clipw = 600;
        map.cliph = 300;
        map.repaint();
        //
        return true;
    }
    //
    //---------------------
    //--- update values ---
    //---------------------
    //
    public void apply() {
        //
        //get string values from text fields
        //
        s1 = fc1.getText();
        s2 = fc2.getText();
        s3 = fc3.getText();
        s4 = fc4.getText();
        //
        //convert string values to numbers
        //
        if (! (s1.equals(""))) {
            D1 = Double.valueOf(s1);
            d1 = D1.doubleValue();
        }
        if (! (s2.equals(""))) {
            D2 = Double.valueOf(s2);
            d2 = D2.doubleValue();
        }
        if (! (s3.equals(""))) {
            D3 = Double.valueOf(s3);
            d3 = D3.doubleValue();
        }
        if (! (s4.equals(""))) {
            D4 = Double.valueOf(s4);
            d4 = D4.doubleValue();
        }
        //
        //update values
        //
        if (curtype == 1) {
            curpipe.diameter = (d1 / 100);
            curpipe.friction = d2;
            curpipe.calculate();
            curpipe.toapp.diameter = (d1 / 100);
            curpipe.toapp.calculate();
        }
        if (curtype == 2) {
            if (curapp.type.equals("pump")) {
                curapp.hp = d1;
            }
            if (curapp.type.equals("joint")) {
                curapp.k = d1;
            }
            if (curapp.type.equals("valve")) {
                curapp.k = d1;
            }
            if (curapp.type.equals("turbine")) {
                curapp.ht = d1;
            }
            curapp.calculate();
        }
    }
    //
    //-----------------
    //--- calculate ---
    //-----------------
    //
    public void calculate() {
        //
        //get cptotal
        //
        cptotal = 0;
        thispipe = pipe[1];
        eof = false;
        while (! eof) {
            cptotal = cptotal + thispipe.cp;
            if (thispipe.toapp.x == 450) {
                eof = true;
            }
            if (thispipe.toapp.x < 450) {
                thispipe = thispipe.toapp.topipe;
            }
        }
        //
        //get cmtotal, hptotal, httotal
        //
        cmtotal = 0;
        hptotal = 0;
        httotal = 0;
        cmtotal = cmtotal + app[1].cm;
        lastapp = app[1];
        eof = false;
        while (! eof) {
            thisapp = lastapp.topipe.toapp;
            if (thisapp.type.equals("pump")) {
                hptotal = hptotal + thisapp.hp;
            }
            if (thisapp.type.equals("joint")) {
                cmtotal = cmtotal + thisapp.cm;
            }
            if (thisapp.type.equals("valve")) {
                cmtotal = cmtotal + thisapp.cm;
            }
            if (thisapp.type.equals("turbine")) {
                httotal = httotal + thisapp.ht;
            }
            if (thisapp.x == 450) {
                eof = true;
            }
            lastapp = thisapp;
        }
        //
        //ellevel and erlevel
        //
        if (llevel >= 150) {
            ellevel = 150.00;
        }
        if (llevel < 150) {
            ellevel = (double) llevel;
        }
        if (rlevel >= 150) {
            erlevel = 150.00;
        }
        if (rlevel < 150) {
            erlevel = (double) rlevel;
        }
        //
        //get fd
        //
        //0 = no flow
        //1 = right to left
        //2 = left to right
        //
        if (ellevel == erlevel) {
            fd = 0;
        }
        if (ellevel > erlevel) {
            fd = 1;
        }
        if (ellevel < erlevel) {
            fd = 2;
        }
        //
        //get q
        //
        if (fd == 0) {
            q = 0;
        }
        if (fd == 1) {
            q = java.lang.Math.sqrt((((ellevel / 5.00) - (erlevel / 5.00) + hptotal - httotal) / (cptotal + cmtotal)));
        }
        if (fd == 2) {
            q = java.lang.Math.sqrt((((erlevel / 5.00) - (ellevel / 5.00) + hptotal - httotal) / (cptotal + cmtotal)));
        }
        //
        //get hgl and egl
        //
        deglmax = (ellevel / 5.00);
        deglmin = (ellevel / 5.00);
        dhglmax = (ellevel / 5.00);
        dhglmin = (ellevel / 5.00);
        if (fd == 0) {
            pipe[1].fromegl = (ellevel / 5.00);
            pipe[1].fromhgl = (ellevel / 5.00);
            pipe[1].toegl = (ellevel / 5.00);
            pipe[1].tohgl = (ellevel / 5.00);
            lastpipe = pipe[1];
            eof = false;
            if (lastpipe.toapp.x == 450) {
                eof = true;
            }
            while (! eof) {
                thispipe = lastpipe.toapp.topipe;
                thispipe.fromegl = (ellevel / 5.00);
                thispipe.fromhgl = (ellevel / 5.00);
                thispipe.toegl = (ellevel / 5.00);
                thispipe.tohgl = (ellevel / 5.00);
                if (thispipe.toapp.x == 450) {
                    eof = true;
                }
                lastpipe = thispipe;
            }
        }
        if (fd == 1) {
            pipe[1].fromegl = (ellevel / 5.00) - pipe[1].fromapp.gethl(q);
            deglmax = pipe[1].fromegl;
            deglmin = pipe[1].fromegl;
            pipe[1].fromhgl = pipe[1].fromegl + pipe[1].getvh(q);
            dhglmax = pipe[1].fromhgl;
            dhglmin = pipe[1].fromhgl;
            pipe[1].toegl = pipe[1].fromegl - pipe[1].gethl(q);
            if (pipe[1].toegl < deglmax) {
                deglmax = pipe[1].toegl;
            }
            if (pipe[1].toegl > deglmin) {
                deglmin = pipe[1].toegl;
            }
            pipe[1].tohgl = pipe[1].toegl + pipe[1].getvh(q);
            if (pipe[1].tohgl < dhglmax) {
                dhglmax = pipe[1].tohgl;
            }
            if (pipe[1].tohgl > dhglmin) {
                dhglmin = pipe[1].tohgl;
            }
            lastpipe = pipe[1];
            eof = false;
            if (lastpipe.toapp.x == 450) {
                eof = true;
            }
            while (! eof) {
                thispipe = lastpipe.toapp.topipe;
                thispipe.fromegl = lastpipe.toegl - thispipe.fromapp.gethl(q);
                if (thispipe.fromegl < deglmax) {
                    deglmax = thispipe.fromegl;
                }
                if (thispipe.fromegl > deglmin) {
                    deglmin = thispipe.fromegl;
                }
                thispipe.fromhgl = thispipe.fromegl + thispipe.getvh(q);
                if (thispipe.fromhgl < dhglmax) {
                    dhglmax = thispipe.fromhgl;
                }
                if (thispipe.fromhgl > dhglmin) {
                    dhglmin = thispipe.fromhgl;
                }
                thispipe.toegl = thispipe.fromegl - thispipe.gethl(q);
                if (thispipe.toegl < deglmax) {
                    deglmax = thispipe.toegl;
                }
                if (thispipe.toegl > deglmin) {
                    deglmin = thispipe.toegl;
                }
                thispipe.tohgl = thispipe.toegl + thispipe.getvh(q);
                if (thispipe.tohgl < dhglmax) {
                    dhglmax = thispipe.tohgl;
                }
                if (thispipe.tohgl > dhglmin) {
                    dhglmin = thispipe.tohgl;
                }
                if (thispipe.toapp.x == 450) {
                    eof = true;
                }
                lastpipe = thispipe;
            }
        }
        if (fd == 2) {
            pipe[1].fromegl = (ellevel / 5.00) + pipe[1].fromapp.gethl(q);
            deglmax = pipe[1].fromegl;
            deglmin = pipe[1].fromegl;
            pipe[1].fromhgl = pipe[1].fromegl + pipe[1].getvh(q);
            dhglmax = pipe[1].fromhgl;
            dhglmin = pipe[1].fromhgl;
            pipe[1].toegl = pipe[1].fromegl + pipe[1].gethl(q);
            if (pipe[1].toegl < deglmax) {
                deglmax = pipe[1].toegl;
            }
            if (pipe[1].toegl > deglmin) {
                deglmin = pipe[1].toegl;
            }
            pipe[1].tohgl = pipe[1].toegl + pipe[1].getvh(q);
            if (pipe[1].tohgl < dhglmax) {
                dhglmax = pipe[1].tohgl;
            }
            if (pipe[1].tohgl > dhglmin) {
                dhglmin = pipe[1].tohgl;
            }
            lastpipe = pipe[1];
            eof = false;
            if (lastpipe.toapp.x == 450) {
                eof = true;
            }
            while (! eof) {
                thispipe = lastpipe.toapp.topipe;
                thispipe.fromegl = lastpipe.toegl + thispipe.fromapp.gethl(q);
                if (thispipe.fromegl < deglmax) {
                    deglmax = thispipe.fromegl;
                }
                if (thispipe.fromegl > deglmin) {
                    deglmin = thispipe.fromegl;
                }
                thispipe.fromhgl = thispipe.fromegl + thispipe.getvh(q);
                if (thispipe.fromhgl < dhglmax) {
                    dhglmax = thispipe.fromhgl;
                }
                if (thispipe.fromhgl > dhglmin) {
                    dhglmin = thispipe.fromhgl;
                }
                thispipe.toegl = thispipe.fromegl + thispipe.gethl(q);
                if (thispipe.toegl < deglmax) {
                    deglmax = thispipe.toegl;
                }
                if (thispipe.toegl > deglmin) {
                    deglmin = thispipe.toegl;
                }
                thispipe.tohgl = thispipe.toegl + thispipe.getvh(q);
                if (thispipe.tohgl < dhglmax) {
                    dhglmax = thispipe.tohgl;
                }
                if (thispipe.tohgl > dhglmin) {
                    dhglmin = thispipe.tohgl;
                }
                if (thispipe.toapp.x == 450) {
                    eof = true;
                }
                lastpipe = thispipe;
            }
        }
        if ((erlevel / 5.00) < deglmax) {
            deglmax = (erlevel / 5.00);
        }
        if ((erlevel / 5.00) > deglmin) {
            deglmin = (erlevel / 5.00);
        }
        if ((erlevel / 5.00) < dhglmax) {
            dhglmax = (erlevel / 5.00);
        }
        if ((erlevel / 5.00) > dhglmin) {
            dhglmin = (erlevel / 5.00);
        }
        eglmax = 40 - (int) deglmax;
        eglmin = 40 - (int) deglmin;
        hglmax = 40 - (int) dhglmax;
        hglmin = 40 - (int) dhglmin;
    }
    //
    //------------------------
    //--- update edit area ---
    //------------------------
    //
    public void updateedit() {
        if (curtype == 1) {
            lc1.setText("Diameter [cm]");
            fc1.setText(String.valueOf((curpipe.diameter * 100)));
            fc1.setEditable(true);
            lc2.setText("Friction Factor []");
            fc2.setText(String.valueOf(curpipe.friction));
            fc2.setEditable(true);
            lc3.setText("Length [m]");
            fc3.setText(String.valueOf(curpipe.length));
            fc3.setEditable(false);
            lc4.setText("");
            fc4.setText("");
            fc4.setEditable(false);
        }
        if (curtype == 2) {
            if (curapp.type.equals("pump")) {
                lc1.setText("Pump Head [m]");
                fc1.setText(String.valueOf(curapp.hp));
                fc1.setEditable(true);
                lc2.setText("");
                fc2.setText("");
                fc2.setEditable(false);
                lc3.setText("");
                fc3.setText("");
                fc3.setEditable(false);
                lc4.setText("");
                fc4.setText("");
                fc4.setEditable(false);
            }
            if (curapp.type.equals("joint")) {
                lc1.setText("Loss Coefficient []");
                fc1.setText(String.valueOf(curapp.k));
                fc1.setEditable(true);
                lc2.setText("");
                fc2.setText("");
                fc2.setEditable(false);
                lc3.setText("");
                fc3.setText("");
                fc3.setEditable(false);
                lc4.setText("");
                fc4.setText("");
                fc4.setEditable(false);
            }
            if (curapp.type.equals("valve")) {
                lc1.setText("Loss Coefficient []");
                fc1.setText(String.valueOf(curapp.k));
                lc2.setText("");
                fc2.setText("");
                fc2.setEditable(false);
                lc3.setText("");
                fc3.setText("");
                fc3.setEditable(false);
                lc4.setText("");
                fc4.setText("");
                fc4.setEditable(false);
            }
            if (curapp.type.equals("turbine")) {
                lc1.setText("Turbine Head [m]");
                fc1.setText(String.valueOf(curapp.ht));
                lc2.setText("");
                fc2.setText("");
                fc2.setEditable(false);
                lc3.setText("");
                fc3.setText("");
                fc3.setEditable(false);
                lc4.setText("");
                fc4.setText("");
                fc4.setEditable(false);
            }
        }
    }
    //
    //---------------
    //--- add app ---
    //---------------
    //
    public void addapp(String type, int x, Pipe thepipe, App theapp) {
        //
        //-- create new app ---
        //
        newapp = new App();
        newapp.type = type;
        newapp.x = x;
        if (type.equals("pump")) {
            newapp.hp = theapp.hp;
        }
        if ((type.equals("joint")) || (type.equals("valve"))){
            newapp.k = theapp.k;
        }
        if (type.equals("turbine")) {
            newapp.ht = theapp.ht;
        }
        //
        //--- create a new pipe ---
        //
        newpipe = new Pipe();
        newpipe.diameter = thepipe.diameter;
        newpipe.friction = thepipe.friction;
        //
        //--- update connections ---
        //
        newapp.frompipe = thepipe;
        newapp.topipe = newpipe;
        //
        newpipe.fromapp = newapp;
        newpipe.toapp = thepipe.toapp;
        //
        thepipe.toapp = newapp;
        //
        newpipe.toapp.frompipe = newpipe;
        //
        //--- recalculate objects ---
        //
        newpipe.calculate();
        thepipe.calculate();
        newapp.calculate();
        newpipe.toapp.calculate();
        //
        //
        //--- make new app current ---
        //
        curtype = 2;
        curapp = newapp;
    }
    //
    //------------------
    //--- delete app ---
    //------------------
    //
    public void delapp(App delapp) {
        //
        //--- stretch frompipe ---
        //
        newtoapp = delapp.topipe.toapp;
        //
        delapp.frompipe.toapp = newtoapp;
        delapp.frompipe.calculate();
        //
        //--- update newtoapp ---
        //
        newtoapp.frompipe = delapp.frompipe;
        newtoapp.calculate();
    }
}
//
//----------------------------
//----------------------------
//--- map class definition ---
//----------------------------
//----------------------------
//
class Map extends Panel {
    //
    //-----------------
    //--- variables ---
    //-----------------
    //
    double length, appdistdn, pipdistdn, levdistdn;
    double appdist, pipdist, appdistup, pipdistup, distance;
    Utflow Utflow;
    Pipe newpipe, topipe, frompipe, pipclos, pipclosup, pipclosdn, lastpipe, thispipe;
    App appclos, appclosup, appclosdn, appmove, lastapp, thisapp;
    int dnx, dny, dragx, dragy, movex, movey, tox, toy, levclosdn;
    int offx, offy, clipw, cliph;
    int i, j, k, m, n;
    int mode, valid, corx, cory, prevdragx, prevdragy, xdist, ydist;
    String addtype;
    boolean eof;
    Image oi, soi;
    Graphics g, og, sog;
    ImageObserver io, sio;
    //
    //-------------------------
    //--- mouse down method ---
    //-------------------------
    //
    public boolean mouseDown(Event evt, int x, int y) {
        //
        mode = 0;
        if (new Rectangle(55, 5, 20, 15).inside(x, y)) {
            mode = 1;
            addtype = "pump";
            corx = x - 61;
            cory = y - 10;
        }
        if (new Rectangle(55, 20, 20, 15).inside(x, y)) {
            mode = 1;
            addtype = "joint";
            corx = x - 61;
            cory = y - 25;
        }
        if (new Rectangle(55, 35, 20, 15).inside(x, y)) {
            mode = 1;
            addtype = "valve";
            corx = x - 61;
            cory = y - 40;
        }
        if (new Rectangle(55, 50, 20, 15).inside(x, y)) {
            mode = 1;
            addtype = "turbine";
            corx = x - 61;
            cory = y - 55;
        }
        //
        //find closest app
        //
        findcapp(x, y);
        appclosdn = appclos;
        appdistdn = appdist;
        //
        //find closest pipe
        //
        findcpipe(x, y);
        pipclosdn = pipclos;
        pipdistdn = pipdist;
        //
        //find closest lev
        //
        levclosdn = 0;
        levdistdn = 1000;
        if ((100 < x ) && ( 150 > x)) {
            levclosdn = 1;
            levdistdn = java.lang.Math.sqrt(java.lang.Math.pow((Utflow.llevel - y), 2));
        }
        if ((450 < x ) && ( 500 > x)) {
            levclosdn = 2;
            levdistdn = java.lang.Math.sqrt(java.lang.Math.pow((Utflow.rlevel - y), 2));
        }
        //
        //select/move app
        //
        Utflow.apply();
        //
        if (mode == 0) {
            if ((appdistdn <= 10) && (pipdistdn <= 10)) {
                Utflow.curtype = 2;
                Utflow.curapp = appclosdn;
                appmove = appclosdn;
                corx = x - appclosdn.x;
                cory = y - 150;
                mode = 2;
            }
            if ((appclosdn.x == 150) || (appclosdn.x == 450)){
                mode = 0;
            }
            if (appdistdn > 10) {
                if (pipdistdn <= 10) {
                    Utflow.curtype = 1;
                    Utflow.curpipe = pipclosdn;
                }
            }
        }
        //
        //move lev
        //
        if (levdistdn <= 5) {
            if (levclosdn == 1) {
                corx = 0;
                cory = y - Utflow.llevel;
                mode = 101;
            }
            if (levclosdn == 2) {
                mode = 102;
            }
        }
        dnx = x;
        dny = y;
        dragx = x;
        dragy = y;
        prevdragx = dragx;
        prevdragy = dragy;
        offx = 0;
        offy = 0;
        clipw = 600;
        cliph = 300;
        repaint();
        return true;
    }
    //
    //-------------------------
    //--- mouse drag method ---
    //-------------------------
    //
    public boolean mouseDrag(Event evt, int x, int y) {
        prevdragx = dragx;
        prevdragy = dragy;
        dragx = x;
        dragy = y;
        xdist = ((int) java.lang.Math.sqrt(java.lang.Math.pow((prevdragx - dragx), 2))) + 10;
        ydist = ((int) java.lang.Math.sqrt(java.lang.Math.pow((prevdragy - dragy), 2))) + 10;
        if ((mode == 1) || (mode == 2)) {
            offx = dragx - xdist;
            offy = dragy - ydist;
            clipw = 1 + 2 * xdist;
            cliph = 1 + 2 * ydist;
        }
        if (mode == 101) {
            offx = 101;
            offy = dragy - ydist;
            clipw = 49;
            cliph = 1 + 2 * ydist;
        }
        if (mode == 102) {
            offx = 451;
            offy = dragy - ydist;
            clipw = 49;
            cliph = 1 + 2 * ydist;
        }
        repaint();
        return true;
    }
    //
    //-----------------------
    //--- mouse up method ---
    //-----------------------
    //
    public boolean mouseUp(Event evt, int x, int y) {
        //
        tox = x;
        toy = y;
        //
        //find closest app
        //
        findcapp(x, y);
        appclosup = appclos;
        appdistup = appdist;
        //
        //find closest pip
        //
        findcpipe(x, y);
        pipclosup = pipclos;
        pipdistup = pipdist;
        //
        //--- action for add app ---
        //
        if (mode == 1) {
            valid = 1;
            if (pipdistup > 5) {
                valid = 0;
            }
            if (appdistup <= 5) {
                valid = 0;
            }
            if (valid == 1) {
                Utflow.addapp(addtype, x, pipclosup, (new App()));
            }
        }
        //
        //--- action for move app ---
        //
        if (mode == 2) {
            valid = 1;
            if (pipdistup > 10) {
                valid = 0;
            }
            if (appdistup <= 10) {
                valid = 0;
            }
            if (valid == 1) {
                Utflow.addapp(appmove.type, x, pipclosup, appmove);
                Utflow.delapp(appmove);
            }
        }
        //
        //--- action for trash ---
        //
        if (new Rectangle(55, 65, 20, 15).inside(x, y)) {
            if (mode == 2) {
                Utflow.delapp(appmove);
            }
        }
        //
        //--- action for move lev ---
        //
        if ((mode == 101) && (y <= 200) && (y >= 20)) {
            Utflow.llevel = y;
        }
        if ((mode == 102) && (y <= 200) && (y >= 20)) {
            Utflow.rlevel = y;
        }
        //
        //--- misc ---
        //
        mode = 0;
        Utflow.calculate();
        Utflow.updateedit();
        offx = 0;
        offy = 0;
        clipw = 600;
        cliph = 300;
        repaint();
        return true;
    }
    //
    //-------------------------------
    //--- find closest app method ---
    //-------------------------------
    //
    public void findcapp(int x, int y) {
        appclos = new App();
        appdist = 1000;
        distance = java.lang.Math.sqrt(java.lang.Math.pow((Utflow.app[1].x - x), 2));
        appclos = Utflow.app[1];
        appdist = distance;
        lastapp = Utflow.app[1];
        eof = false;
        while (! eof) {
            thisapp = lastapp.topipe.toapp;
            distance = java.lang.Math.sqrt(java.lang.Math.pow((thisapp.x - x), 2));
            if (distance < appdist) {
                appclos = thisapp;
                appdist = distance;
            }
            if (thisapp.x == 450) {
                eof = true;
            }
            lastapp = thisapp;
        }
    }
    //
    //--------------------------------
    //--- find closest pipe method ---
    //--------------------------------
    //
    public void findcpipe(int x, int y) {
        pipclos = new Pipe();
        pipdist = 1000;
        pipclos = Utflow.pipe[1];
        pipdist = java.lang.Math.sqrt(java.lang.Math.pow((150 - y), 2));
        lastpipe = Utflow.pipe[1];
        eof = false;
        if (lastpipe.toapp.x == 450) {
            eof = true;
        }
        while (! eof) {
            thispipe = lastpipe.toapp.topipe;
            if ((x >= thispipe.fromapp.x) && (x < thispipe.toapp.x)) {
                pipclos = thispipe;
                pipdist = java.lang.Math.sqrt(java.lang.Math.pow((150 - y), 2));
            }
            if ((thispipe.fromapp.x == 150) && (x < 150)) {
                pipclos = thispipe;
                pipdist = java.lang.Math.sqrt((java.lang.Math.pow((150 - y), 2) + (java.lang.Math.pow((150 - x), 2))));
            }
            if ((thispipe.toapp.x == 450) && (x >= 450)) {
                pipclos = thispipe;
                pipdist = java.lang.Math.sqrt((java.lang.Math.pow((150 - y), 2) + (java.lang.Math.pow((450 - x), 2))));
            }
            if (thispipe.toapp.x == 450) {
                eof = true;
            }
            lastpipe = thispipe;
        }
    }
    //
    //--------------------
    //--- init method ---
    //--------------------
    //
    public void init() {
        //
        //--- image set up ---
        //
        soi = createImage(600, 300);
        sog = soi.getGraphics();
        ImageObserver sio = Utflow;
        //
        //--- background ---
        //
        sog.setColor(Color.lightGray);
        sog.fillRect(0, 0, 600, 300);
        //
        //--- coordinate system ---
        //
        sog.setColor(Color.gray);
        sog.drawString("0", 146, 227);
        sog.drawString("10", 193, 227);
        sog.drawString("20", 243, 227);
        sog.drawString("30", 293, 227);
        sog.drawString("40", 343, 227);
        sog.drawString("50", 393, 227);
        sog.drawString("60 [m]", 443, 227);
        sog.drawString("0", 520, 203);
        sog.drawString("10", 520, 153);
        sog.drawString("20", 520, 103);
        sog.drawString("30 [m]", 520, 53);
        sog.drawLine(150, 210, 450, 210);
        sog.drawLine(150, 30, 150, 215);
        sog.drawLine(200, 30, 200, 215);
        sog.drawLine(250, 30, 250, 215);
        sog.drawLine(300, 30, 300, 215);
        sog.drawLine(350, 30, 350, 215);
        sog.drawLine(400, 30, 400, 215);
        sog.drawLine(450, 30, 450, 215);
        sog.drawLine(510, 30, 510, 200);
        sog.drawLine(100, 200, 515, 200);
        sog.drawLine(100, 150, 515, 150);
        sog.drawLine(100, 100, 515, 100);
        sog.drawLine(100, 50, 515, 50);
        //
        //--- menu and flow info area---
        //
        sog.setColor(Color.green);
        sog.fillOval(61, 10, 8, 8);
        sog.setColor(Color.magenta);
        sog.fillOval(61, 25, 8, 8);
        sog.setColor(Color.cyan);
        sog.fillOval(61, 40, 8, 8);
        sog.setColor(Color.red);
        sog.fillOval(61, 55, 8, 8);
        sog.setColor(Color.black);
        sog.drawRect(5, 5, 70, 75);
        sog.drawLine(55, 5, 55, 80);
        sog.drawLine(5, 20, 75, 20);
        sog.drawLine(5, 35, 75, 35);
        sog.drawLine(5, 50, 75, 50);
        sog.drawLine(5, 65, 75, 65);
        sog.drawString("Pump", 10, 17);
        sog.drawString("Joint", 10, 31);
        sog.drawString("Valve", 10, 47);
        sog.drawString("Turbine", 10, 62);
        sog.drawString("Trash", 10, 77);
        sog.drawRect(5, 100, 70, 125);
        sog.drawLine(5, 130, 75, 130);
        sog.drawLine(5, 175, 75, 175);
        sog.drawString("Flow Rate", 10, 112);
        sog.drawString("Mx/Mn [m]", 10, 142);
        sog.drawString("Res. Elev.", 10, 187);
        //
        //--- reservoirs ---
        //
        sog.drawLine(100, 20, 100, 200);
        sog.drawLine(99, 20, 99, 200);
        sog.drawLine(100, 200, 150, 200);
        sog.drawLine(99, 201, 151, 201);
        sog.drawLine(150, 200, 150, 20);
        sog.drawLine(151, 201, 151, 20);
        sog.drawLine(96, 20, 100, 20);
        sog.drawLine(96, 21, 100, 21);
        sog.drawLine(150, 20, 154, 20);
        sog.drawLine(150, 21, 154, 21);
        //
        sog.drawLine(450, 20, 450, 200);
        sog.drawLine(449, 20, 449, 200);
        sog.drawLine(450, 200, 500, 200);
        sog.drawLine(449, 201, 501, 201);
        sog.drawLine(500, 200, 500, 20);
        sog.drawLine(501, 201, 501, 20);
        sog.drawLine(446, 20, 450, 20);
        sog.drawLine(446, 21, 450, 21);
        sog.drawLine(500, 20, 504, 20);
        sog.drawLine(500, 21, 504, 21);
    }
    //
    //---------------------
    //--- update method ---
    //---------------------
    //
    public void update(Graphics g) {
        paint(g);
    }
    //
    //--------------------
    //--- paint method ---
    //--------------------
    //
    public void paint(Graphics g) {
        //
        //--- paint parameters ---
        //
        g.clipRect(offx, offy, clipw, cliph);
        //
        //--- image set up ---
        //
        oi = createImage(clipw, cliph);
        og = oi.getGraphics();
        ImageObserver io = Utflow;
        //
        //--- background ---
        //
        og.drawImage(soi, - offx, - offy, sio);     
        //
        //--- menu and flow info area---
        //
        og.drawString((String.valueOf(((int) (Utflow.q * 1000))) + " L/s"), 10 - offx, 127 - offy);
        og.drawString(("EGL " + String.valueOf(Utflow.eglmax) + "/" + String.valueOf(Utflow.eglmin)), 10 - offx, 157 - offy);
        og.drawString(("HGL " + String.valueOf(Utflow.hglmax) + "/" + String.valueOf(Utflow.hglmin)), 10 - offx, 172 - offy);
        og.drawString(("Left  " + String.valueOf(((200 - Utflow.llevel) / 5)) + " m"), 10 - offx, 202 - offy);
        og.drawString(("Right " + String.valueOf(((200 - Utflow.rlevel) / 5)) + " m"), 10 - offx, 217 - offy);
        //
        //--- water levels ---
        //
        og.setColor(Color.blue);
        if (! (mode == 101)) {
            og.fillRect(101 - offx, Utflow.llevel - offy, 49, 200 - Utflow.llevel);
            og.drawLine(125 - offx, Utflow.llevel - offy, 125 - offx, Utflow.llevel - offy);
            og.drawLine(126 - offx, Utflow.llevel - offy - 1, 124 - offx, Utflow.llevel - offy - 1);
            og.drawLine(127 - offx, Utflow.llevel - offy - 2, 123 - offx, Utflow.llevel - offy - 2);
            og.drawLine(128 - offx, Utflow.llevel - offy - 3, 122 - offx, Utflow.llevel - offy - 3);
            og.drawLine(129 - offx, Utflow.llevel - offy - 4, 121 - offx, Utflow.llevel - offy - 4);
            og.drawLine(130 - offx, Utflow.llevel - offy - 5, 120 - offx, Utflow.llevel - offy - 5);
        }
        if (mode == 101) {
            if (dragy < 20) {
                og.fillRect(101 - offx, 20 - offy, 49, 180);
                og.drawLine(125 - offx, 20 - offy, 125 - offx, 20 - offy);
                og.drawLine(126 - offx, 19 - offy, 124 - offx, 19 - offy);
                og.drawLine(127 - offx, 18 - offy, 123 - offx, 18 - offy);
                og.drawLine(128 - offx, 17 - offy, 122 - offx, 17 - offy);
                og.drawLine(129 - offx, 16 - offy, 121 - offx, 16 - offy);
                og.drawLine(130 - offx, 15 - offy, 120 - offx, 15 - offy);
            }
            if (dragy > 200) {
                og.drawLine(125 - offx, 200 - offy, 125 - offx, 200 - offy);
                og.drawLine(126 - offx, 199 - offy, 124 - offx, 199 - offy);
                og.drawLine(127 - offx, 198 - offy, 123 - offx, 198 - offy);
                og.drawLine(128 - offx, 197 - offy, 122 - offx, 197 - offy);
                og.drawLine(129 - offx, 196 - offy, 121 - offx, 196 - offy);
                og.drawLine(130 - offx, 195 - offy, 120 - offx, 195 - offy);
            }
            if ((dragy >= 20) && (dragy <= 200)) {
                og.fillRect(101 - offx, dragy - offy, 49, 200 - dragy);
                og.drawLine(125 - offx, dragy - offy, 125 - offx, dragy - offy);
                og.drawLine(126 - offx, dragy - offy - 1, 124 - offx, dragy - offy - 1);
                og.drawLine(127 - offx, dragy - offy - 2, 123 - offx, dragy - offy - 2);
                og.drawLine(128 - offx, dragy - offy - 3, 122 - offx, dragy - offy - 3);
                og.drawLine(129 - offx, dragy - offy - 4, 121 - offx, dragy - offy - 4);
                og.drawLine(130 - offx, dragy - offy - 5, 120 - offx, dragy - offy - 5);
            }
        }
        if (! (mode == 102)) {
            og.fillRect(451 - offx, Utflow.rlevel - offy, 49, 200 - Utflow.rlevel);
            og.drawLine(475 - offx, Utflow.rlevel - offy, 475 - offx, Utflow.rlevel - offy);
            og.drawLine(476 - offx, Utflow.rlevel - offy - 1, 474 - offx, Utflow.rlevel - offy - 1);
            og.drawLine(477 - offx, Utflow.rlevel - offy - 2, 473 - offx, Utflow.rlevel - offy - 2);
            og.drawLine(478 - offx, Utflow.rlevel - offy - 3, 472 - offx, Utflow.rlevel - offy - 3);
            og.drawLine(479 - offx, Utflow.rlevel - offy - 4, 471 - offx, Utflow.rlevel - offy - 4);
            og.drawLine(480 - offx, Utflow.rlevel - offy - 5, 470 - offx, Utflow.rlevel - offy - 5);
        }
        if (mode == 102) {
            if (dragy < 20) {
                og.fillRect(451 - offx, 20 - offy, 49, 180);
                og.drawLine(475 - offx, 20 - offy, 475 - offx, 20 - offy);
                og.drawLine(476 - offx, 19 - offy, 474 - offx, 19 - offy);
                og.drawLine(477 - offx, 18 - offy, 473 - offx, 18 - offy);
                og.drawLine(478 - offx, 17 - offy, 472 - offx, 17 - offy);
                og.drawLine(479 - offx, 16 - offy, 471 - offx, 16 - offy);
                og.drawLine(480 - offx, 15 - offy, 470 - offx, 15 - offy);
            }
            if (dragy > 200) {
                og.drawLine(475 - offx, 200 - offy, 475 - offx, 200 - offy);
                og.drawLine(476 - offx, 199 - offy, 474 - offx, 199 - offy);
                og.drawLine(477 - offx, 198 - offy, 473 - offx, 198 - offy);
                og.drawLine(478 - offx, 197 - offy, 472 - offx, 197 - offy);
                og.drawLine(479 - offx, 196 - offy, 471 - offx, 196 - offy);
                og.drawLine(480 - offx, 195 - offy, 470 - offx, 195 - offy);
            }
            if ((dragy >= 20) && (dragy <= 200)) {
                og.fillRect(451 - offx, dragy - offy, 49, 200 - dragy);
                og.drawLine(475 - offx, dragy - offy, 475 - offx, dragy - offy);
                og.drawLine(476 - offx, dragy - offy - 1, 474 - offx, dragy - offy - 1);
                og.drawLine(477 - offx, dragy - offy - 2, 473 - offx, dragy - offy - 2);
                og.drawLine(478 - offx, dragy - offy - 3, 472 - offx, dragy - offy - 3);
                og.drawLine(479 - offx, dragy - offy - 4, 471 - offx, dragy - offy - 4);
                og.drawLine(480 - offx, dragy - offy - 5, 470 - offx, dragy - offy - 5);
            }
        }
        //
        //--- pipes ---
        //
        thispipe = Utflow.pipe[1];
        eof = false;
        while (! eof) {
            if (thispipe.diameter < 0.20) {
                og.drawLine(thispipe.fromapp.x - offx, 150 - offy, thispipe.toapp.x - offx, 150 - offy);
            }
            if ((thispipe.diameter >= 0.20) && (thispipe.diameter < 0.30)) {
                og.drawLine(thispipe.fromapp.x - offx, 149 - offy, thispipe.toapp.x - offx, 149 - offy);
                og.drawLine(thispipe.fromapp.x - offx, 151 - offy, thispipe.toapp.x - offx, 151 - offy);
            }
            if ((thispipe.diameter >= 0.30) && (thispipe.diameter < 0.40)) {
                og.drawLine(thispipe.fromapp.x - offx, 148 - offy, thispipe.toapp.x - offx, 148 - offy);
                og.drawLine(thispipe.fromapp.x - offx, 152 - offy, thispipe.toapp.x - offx, 152 - offy);
            }
            if (thispipe.diameter >= 0.40) {
                og.drawLine(thispipe.fromapp.x - offx, 147 - offy, thispipe.toapp.x - offx, 147 - offy);
                og.drawLine(thispipe.fromapp.x - offx, 153 - offy, thispipe.toapp.x - offx, 153 - offy);
            }
            if (Utflow.curtype == 1) {
                if (thispipe == Utflow.curpipe) {
                    og.setColor(Color.yellow);
                    if (thispipe.diameter < 0.20) {
                        og.drawLine(thispipe.fromapp.x - offx, 149 - offy, thispipe.toapp.x - offx, 149 - offy);
                        og.drawLine(thispipe.fromapp.x - offx, 151 - offy, thispipe.toapp.x - offx, 151 - offy);
                    }
                    if ((thispipe.diameter >= 0.20) && (thispipe.diameter < 0.30)) {
                        og.drawLine(thispipe.fromapp.x - offx, 148 - offy, thispipe.toapp.x - offx, 148 - offy);
                        og.drawLine(thispipe.fromapp.x - offx, 152 - offy, thispipe.toapp.x - offx, 152 - offy);
                    }
                    if ((thispipe.diameter >= 0.30) && (thispipe.diameter < 0.40)) {
                        og.drawLine(thispipe.fromapp.x - offx, 147 - offy, thispipe.toapp.x - offx, 147 - offy);
                        og.drawLine(thispipe.fromapp.x - offx, 153 - offy, thispipe.toapp.x - offx, 153 - offy);
                    }
                    if (thispipe.diameter >= 0.40) {
                        og.drawLine(thispipe.fromapp.x - offx, 146 - offy, thispipe.toapp.x - offx, 146 - offy);
                        og.drawLine(thispipe.fromapp.x - offx, 154 - offy, thispipe.toapp.x - offx, 154 - offy);
                    }
                    og.setColor(Color.blue);
               }
            }
            if (thispipe.toapp.x == 450) {
                eof = true;
            }
            if (thispipe.toapp.x < 450) {
                thispipe = thispipe.toapp.topipe;
            }
        }
        //
        //--- apps ---
        //
        og.setColor(Color.magenta);
        og.fillOval((Utflow.app[1].x - offx - 4), (150 - offy - 4), 8, 8);
        if ((Utflow.curtype == 2) && (Utflow.app[1] == Utflow.curapp)) {
            og.setColor(Color.yellow);
            og.drawOval(Utflow.app[1].x - offx - 4, 146 - offy, 8, 8);
            og.drawOval(Utflow.app[1].x - offx - 5, 145 - offy, 9, 9);
        }
        lastapp = Utflow.app[1];
        eof = false;
        while (! eof) {
            thisapp = lastapp.topipe.toapp;
            og.setColor(Color.green);
            if (thisapp.type.equals("joint")) {
                og.setColor(Color.magenta);
             }
            if (thisapp.type.equals("valve")) {
                og.setColor(Color.cyan);
             }
            if (thisapp.type.equals("turbine")) {
                og.setColor(Color.red);
            }
            og.fillOval(thisapp.x - offx - 4, 146 - offy, 8, 8);
            if ((Utflow.curtype == 2) && (thisapp == Utflow.curapp)) {
                og.setColor(Color.yellow);
                og.drawOval(thisapp.x - offx - 4, 146 - offy, 8, 8);
                og.drawOval(thisapp.x - offx - 5, 145 - offy, 9, 9);
            }
            if (thisapp.x == 450) {
                eof = true;
            }
            lastapp = thisapp;
        }
        //
        //--- hgl and egl ---
        //
        og.setColor(Color.blue);
        og.drawLine(Utflow.pipe[1].fromapp.x - offx, ((int) (5 * Utflow.pipe[1].fromhgl) - offy), Utflow.pipe[1].toapp.x - offx, ((int) (5 * Utflow.pipe[1].tohgl) - offy));
        og.setColor(Color.red);
        og.drawLine(Utflow.pipe[1].fromapp.x - offx, ((int) (5 * Utflow.pipe[1].fromegl) - offy), Utflow.pipe[1].toapp.x - offx, ((int) (5 * Utflow.pipe[1].toegl) - offy));
        lastpipe = Utflow.pipe[1];
        eof = false;
        if (lastpipe.toapp.x == 450) {
            eof = true;
        }
        while (! eof) {
            thispipe = lastpipe.toapp.topipe;
            og.setColor(Color.blue);
            og.drawLine(thispipe.fromapp.x - offx, ((int) (5 * lastpipe.tohgl) - offy), thispipe.fromapp.x - offx, ((int) (5 * thispipe.fromhgl) - offy));
            og.drawLine(thispipe.fromapp.x - offx, ((int) (5 * thispipe.fromhgl) - offy), thispipe.toapp.x - offx, ((int) (5 * thispipe.tohgl) - offy));
            og.setColor(Color.red);
            og.drawLine(thispipe.fromapp.x - offx, ((int) (5 * lastpipe.toegl) - offy), thispipe.fromapp.x - offx, ((int) (5 * thispipe.fromegl) - offy));
            og.drawLine(thispipe.fromapp.x - offx, ((int) (5 * thispipe.fromegl) - offy), thispipe.toapp.x - offx, ((int) (5 * thispipe.toegl) - offy));
            if (thispipe.toapp.x == 450) {
                eof = true;
            }
            lastpipe = thispipe;
        }
        //
        //--- cursor ---
        //
        if (mode == 1) {
            og.setColor(Color.green);
            if (addtype.equals("joint")) {
                og.setColor(Color.magenta);
            }
            if (addtype.equals("valve")) {
                og.setColor(Color.cyan);
            }
            if (addtype.equals("turbine")) {
                og.setColor(Color.red);
            }
            og.fillOval(dragx - offx - corx, dragy - offy - cory, 8, 8);
        }
        if (mode == 2) {
            og.setColor(Color.green);
            if (appmove.type.equals("joint")) {
                og.setColor(Color.magenta);
            }
            if (appmove.type.equals("valve")) {
                og.setColor(Color.cyan);
            }
            if (appmove.type.equals("turbine")) {
                og.setColor(Color.red);
            }
            if (new Rectangle(55, 65, 20, 15).inside(dragx, dragy)) {
                og.setColor(Color.yellow);
            }
            og.fillOval(dragx - offx - 4 - corx, dragy - offy - 4 - cory, 8, 8);
            og.setColor(Color.yellow);
            og.drawOval(dragx - offx - 4 - corx, dragy - offy - 4 - cory, 8, 8);
            og.drawOval(dragx - offx - 5 - corx, dragy - offy - 5 - cory, 9, 9);
            og.drawOval(dragx - offx - 5 - corx, dragy - offy - 5 - cory, 10, 10);
        }
        //
        //--- put image to screen ---
        //
        g.drawImage(oi, offx, offy, io);     
    }
}
//
//flowobject class definition
//
class Flowobject extends Object {
}
//
//pipe class definition
//
class Pipe extends Flowobject {
    //
    double length, diameter, friction, cp, area, hl, v, vh;
    double fromegl, toegl, fromhgl, tohgl;
    App fromapp, toapp;
    //
    public void calculate() {
        length = (((double) (toapp.x - fromapp.x)) / 5.00);
        area = (3.141592654 * diameter * diameter) / 4;
        cp = friction * (length / (diameter * area * area * 2 * 9.81));
    }
    public double gethl(double q2) {
        v = q2 / area;
        hl = (friction * length * v * v) / (diameter * 2 * 9.81);
        return hl;
    }
    public double getvh(double q2) {
        v = q2 / area;
        vh = (v * v) / (2 * 9.81);
        return vh;
    }
}
//
//app class definition
//
class App extends Flowobject {
    //
    String type;
    int x;
    double k, hp, ht, cm, area, q, v, hl, diameter;
    Pipe frompipe, topipe;
    //
    public void calculate() {
        if (x == 150) {
            diameter = topipe.diameter;
        }
        if (x > 150) {
            diameter = frompipe.diameter;
        }
        area = (3.141592654 * diameter * diameter) / 4;
        cm = k * (1 / (area * area * 2 * 9.81));
    }
    public double gethl(double q2) {
        v = q2 / area;
        if (type.equals("pump")) {
            hl = - hp;
        }
        if ((type.equals("joint")) || (type.equals("valve"))) {
            hl = (k * v * v) / (2 * 9.81);
        }
        if (type.equals("turbine")) {
            hl = ht;
        }
        return hl;
    }
}