/*
 * 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 2 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 PURPOUSE. See the GNU
 * General Public License for more details.
 *
 * You should have recieved a copy of the GNU General Public License
 * along with this program; if not write to the Free Software
 * Foundation, inc., 59 Temple Place, Suite 330, Boston MA 02111-1307
 * USA
 */
package run;

import jp.sync.Barrier;
import java.util.Vector;
import jp.lang.*;

/**
 * @author pc58410
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class Worker implements Runnable {
	private Element temporary_element;
	private Node temporary_node;
	private Vector elementlist;
	private Vector nodelist;
	private Barrier barrier;
	private double time, timestep, ttemp;
	private boolean keep_running;
	private boolean autostep;

	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public Worker(Barrier barrier, double time, double timestep, boolean autostep) {
		// TODO Auto-generated method stub
		this.barrier = barrier;
		keep_running = true;
		this.time = time;
		this.timestep = timestep;
		this.autostep = autostep;
		this.elementlist = new Vector();
		this.nodelist = new Vector();
	}

	
	public void addElement(Element el) {
		this.elementlist.addElement(el);
	}
	
	public void removeElement(Element el) {
		this.elementlist.removeElement(el);
	}

	public void addNode(Node node) {
		this.nodelist.addElement(node);
	}
	
	public void removeNode(Node node) {
		this.nodelist.removeElement(node);
	}

	public void run() {
    	int i,j,number_of_integration_points;

    	// Repeat this loop until end time is reached
      	while(keep_running == true) {
 
      		// Main loop sets the time for next loop
      		// Main loop sets the timestep for next loop
      		
      		try {
      			barrier.sync();
      		} catch (InterruptedException e3) {
      			e3.printStackTrace();
      			System.out.println("Worker stopped barrier 1");
      			keep_running = false;
      		}

      		// Each loop, reset the smallest timestep if autostep
      		if (autostep == true) {
      			ttemp = 1E10;
      		}
      		
      		// 	Loop elements
      		for(i = 0; i < elementlist.size(); i++) {
      		    
      		    temporary_element = (Element) elementlist.elementAt(i);
      		    
      		    if (!temporary_element.isDeActivated()) {
      		        // Determine the element local base vectors (local coordinate system)
      		        temporary_element.updateLocalCoordinateSystem();
      		        
      		        // To reduce amount of memory in each element, loop these steps for each integration point
      		        number_of_integration_points = temporary_element.getNumberOfIntegrationPoints();
      		        
      		        for (j = 0; j < number_of_integration_points; j++) {
      		            // Calculate element strain (strain velocity) matrix
      		            temporary_element.calculateStrain(timestep, j);
      		            
      		            // Calculate element stress (stress velocity) matrix
      		            temporary_element.calculateStress(j, timestep);
      		        }
      		        
      		        /* The strains and stresses are now calculated for all integration points. Continue with the
      		         * forces. By knowing all the strains in advance, the thickness reduction
      		         * of shells can be accurately determined */
      		        
      		        for (j = 0; j < number_of_integration_points; j++) {
      		            //	Calculate internal forces
      		            temporary_element.calculateNodalForces(j);
      		        }
      		        
      		        // Calculate external forces (gravity etc)
      		        temporary_element.calculateExternalForces(time);
      		        
      		        // Calculate contact forces
      		        temporary_element.calculateContactForces();
      		        
      		        // Update timestep if needed
      		        if (autostep == true) {
      		            ttemp = temporary_element.checkTimestep(ttemp);
      		        }
      		    }
      		    // End loop
      		}

      		
      		try {
      			barrier.sync();
      		} catch (InterruptedException e) {
      			e.printStackTrace();
      			System.out.println("Worker stopped barrier 2");
      			keep_running = false;      		
      			}
      		
      		// Main loop does some stuff
      		// Main loop reads ttemp to determine smallest timestep

      		try {
      			barrier.sync();
      		} catch (InterruptedException e1) {
      			e1.printStackTrace();
      			keep_running = false;
      			System.out.println("Worker stopped barrier 3");
      		}

      		
      		// Loop Nodes again to clear forces
      		for (i=0 ; i< nodelist.size(); i++) {
      			
      			temporary_node = (Node) nodelist.elementAt(i);
      			
      			if (!temporary_node.isDeActivated()) {
      			    // Clear the nodal forces and prepare for next timestep
      			    temporary_node.clearNodalForces();
      			}
      		}
      		
      		try {
      			barrier.sync();
      		} catch (InterruptedException e2) {
      			e2.printStackTrace();
      			keep_running = false;
      			System.out.println("Worker stopped barrier 4");
      		}
      		
      		
            // Exit cleanly if stopped
            if (Thread.interrupted()) {
                System.out.println("stopping");
                keep_running = false;
            }
        
      	}
      	
    }
	
	/**
	 * @param keep_running The keep_running to set.
	 */
	public void setKeep_running(boolean keep_running) {
		this.keep_running = keep_running;
	}
	/**
	 * @return Returns the time.
	 */
	public double getTime() {
		return time;
	}
	/**
	 * @param time The time to set.
	 */
	public void setTime(double time) {
		this.time = time;
	}
	/**
	 * @return Returns the timestep.
	 */
	public double getTimestep() {
		return timestep;
	}
	/**
	 * @param timestep The timestep to set.
	 */
	public void setTimestep(double timestep) {
		this.timestep = timestep;
	}
	/**
	 * @return Returns the ttemp.
	 */
	public double getTtemp() {
		return ttemp;
	}
	/**
	 * @return Returns the autostep.
	 */
	public boolean isAutostep() {
		return autostep;
	}
	/**
	 * @param autostep The autostep to set.
	 */
	public void setAutostep(boolean autostep) {
		this.autostep = autostep;
	}
}
