/*
 * @(#) DiGraph.java  1.10 10/09/02
 *
 * Copyright ***,  All Rights Reserved.
 * 
 * This software is the proprietary information of ********  
 * Use is subject to license terms.
 * 
 */

// import java packages
//
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 * This class handles the Directional Graph functionalities
 *
 */
public class DiGraph {
    
    //-----------------------------------------------------------------
    //
    // static data members
    //
    //-----------------------------------------------------------------

    //-----------------------------------------------------------------
    //
    // instance data members
    //
    //-----------------------------------------------------------------

    /**
     * basic elements of DiGraph
     */

    // arc objects for stroring vertex (from), vertex (to), weights, and 
    // epsilon 
    //
    public Vector<GraphArc> arcs_d = new Vector<GraphArc>();
    public Vector<Vertex> vertices_d = new Vector<Vertex>();


    //-----------------------------------------------------------------
    //
    // static function members
    //
    //-----------------------------------------------------------------

    //-----------------------------------------------------------------
    //
    // instance function members
    //
    //-----------------------------------------------------------------

    /**
     * default class constructor
     * 
     */
    public DiGraph() {
    }

    /**
     * check errors in the model
     *
     * @param prefix_a prefix to be appended to error message of CData class
     * @param msg_a    message to appended to error message of CData class 
     *
     * @return true if data passes check, false if otherwise
     */
    public boolean check(String prefix_a, String msg_a) {

	// print message
	//
	CData.error_message_d += prefix_a + msg_a + "\n";

	// checking the symbols
	//
	if (arcs_d.size() == 0) {
	    
	    CData.error_message_d += 
		prefix_a + CData.ERR_GRAPH_NO_ARC + "\n";
	    CData.err_flag_d = true;
	    return false;
	}
	
	// checking the symbols
	//
	if (vertices_d.size() == 0) {
	    
	    CData.error_message_d += 
		prefix_a + CData.ERR_GRAPH_NO_VERTEX + "\n";
	    CData.err_flag_d = true;
	    return false;
	}
	
	// write all vertices
	//
	for (int i= 0; i < vertices_d.size(); i++) {
	    Vertex curr_vertex = (Vertex)vertices_d.get(i);
	    String prefix = prefix_a + CData.PREFIX_INDENT;
	    String message = "checking vertex: " + curr_vertex.name_d;
	    CData.printDebugMsg(prefix + message);
	    if ( ! curr_vertex.check(prefix, message) ){
		return false;
	    }
	}

	return true;
    }

    /**
     * class constructor
     * 
     * @param graph_a DiGraph object to be initialized
     */
    public DiGraph(DiGraph graph_a) {

	// copy all vertecies
	//
	for ( int i = 0 ; i < graph_a.vertices_d.size(); i++ ){
	    Vertex curr_vertex = new Vertex((Vertex)graph_a.vertices_d.get(i));
	    curr_vertex.setVisible(true);
	    curr_vertex.setEnabled(true);
	    vertices_d.add(curr_vertex);
	}

	// copy all arcs
	//
	for ( int j = 0 ; j < graph_a.arcs_d.size(); j++ ){
	    GraphArc old_arc = (GraphArc)graph_a.arcs_d.get(j);
	    GraphArc curr_arc = new GraphArc();
	    curr_arc.weights_d = old_arc.weights_d;
	    curr_arc.epsilon_d = old_arc.epsilon_d;
	    arcs_d.add(curr_arc);

	    // set the from and to vertices
	    //
	    int index = graph_a.vertices_d.indexOf(old_arc.from_d);
	    curr_arc.from_d = (Vertex)vertices_d.get(index);
	    index = graph_a.vertices_d.indexOf(old_arc.to_d);
	    curr_arc.to_d = (Vertex)vertices_d.get(index);
	}

    }

    /**
     * checks to see if this graph has the start vertex 
     * 
     * @return true if a vertex in vertices_d vector is a start vertex
     */
    public boolean hasStart() {
	
	for ( int i = 0 ; i < vertices_d.size(); i++ ){
	    if (((Vertex)vertices_d.get(i)).isStart()){
		return true;
	    }
	}
	return false;
    }

    /**
     * checks to see if this graph has the term vertex 
     * 
     * @return true if a vertex in vertices_d vector is a start vertex
     */
    public boolean hasTerm() {
	
	for ( int i = 0 ; i < vertices_d.size(); i++ ){
	    if (((Vertex)vertices_d.get(i)).isTerm()){
		return true;
	    }
	}
	return false;
    }

    /**
     * insert a vertex into the graph
     * 
     * @param vertex_a the vertex to be inserted
     */
    public void insertVertex(Vertex vertex_a) {
	vertices_d.add(vertex_a);
    }

    /**
     * insert an Arc into the graph
     * 
     * @param arc_a the Arc to be inserted
     */
    public void insertArc(GraphArc arc_a) {

	boolean flag = true;
	for ( int i = 0 ; i < arcs_d.size(); i++ ){
	    if ( ((GraphArc)arcs_d.get(i)).from_d == arc_a.from_d
		&& ((GraphArc)arcs_d.get(i)).to_d == arc_a.to_d ){
		flag = false;
		break;
	    }
	}
	if ( flag ){
	    arc_a.from_d.addOutcomingArc(arc_a);
	    arc_a.to_d.addIncomingArc(arc_a);
	    arcs_d.add(arc_a);
	}
    }

    /**
     * remove an Arc from the graph
     * 
     * @param arc_a the Arc to be removed
     */
    public void removeArc(GraphArc arc_a) {
	arc_a.from_d.removeOutcomingArc(arc_a);
	arc_a.to_d.removeIncomingArc(arc_a);
	arcs_d.remove(arc_a);
    }

    /**
     * reset the graph arc weight to equal probability
     * 
     * @param total_a total weight of arcs to be distributed or divided
     */
    public void resetGraphArcWeight(float total_a) {
	
	for ( int i = 0 ; i < arcs_d.size(); i++ ){
	    GraphArc curr_arc = (GraphArc)arcs_d.get(i);
	    Float weight = 
		new Float(total_a/curr_arc.from_d.out_arcs_d.size());
	    curr_arc.weights_d = weight.toString();
	}
    }

    /**
     * find the focused graph arc
     * 
     * @param point_a current point
     * @return graph arc at point
     */
    public GraphArc findFocusGraphArc(Point point_a) {
	
	for ( int i = 0 ; i < arcs_d.size(); i++ ){
	    GraphArc curr_arc = (GraphArc)arcs_d.get(i);
	    if ( curr_arc.isSelected(point_a)){
		return curr_arc;
	    }
	}
	return (GraphArc)null;
    }

    /**
     * find the focused graph vertex
     * 
     * @param point_a current point
     * @return graph vertex at point
     */
    public Vertex findFocusVertex(Point point_a) {
	
	for ( int i = 0 ; i < arcs_d.size(); i++ ){
	    Vertex curr_vertex = (Vertex)vertices_d.get(i);
	    if ( curr_vertex.isSelected(point_a)){
		return curr_vertex;
	    }
	}
	return (Vertex)null;
    }

    /**
     * hide all the vertices
     * 
     */
    public void hideVertices() {
	
	for ( int i = 0 ; i < vertices_d.size(); i++ ){
	    Vertex curr_vertex = (Vertex)vertices_d.get(i);
	    curr_vertex.setVisible(false);
	    curr_vertex.setEnabled(false);
	}
    }

    /**
     * show all the vertices
     * 
     */
    public void showVertices() {
	
	for ( int i = 0 ; i < vertices_d.size(); i++ ){
	    Vertex curr_vertex = (Vertex)vertices_d.get(i);
	    curr_vertex.setVisible(true);
	    curr_vertex.setEnabled(true);
	}
    }

    /**
     * remove a vertex from the DiGraph
     * 
     * @param target_a the vertex to be removed
     */
    public void removeVertex(Vertex target_a) {

	// verify that the vertex to be deleted is valid
	//
	if (target_a == null) {
	    return;
	}

	/*
	// remove all arcs connected to this vertex
	//
	for (int i=0; i<arcs_d.size(); i++) {
	    GraphArc curr_arc = (GraphArc)arcs_d.get(i);
	    if ( curr_arc.from_d == target_a ||
		 curr_arc.to_d == target_a ) {
		arcs_d.remove(curr_arc);
	    }
	}
	*/

	// remove all arcs connected to this vertex
	//
	Vector<GraphArc> removed_arcs = new Vector<GraphArc>();
	for (int i=0; i<arcs_d.size(); i++) {
	    GraphArc curr_arc = (GraphArc)arcs_d.get(i);
	    if ( curr_arc.from_d == target_a ||
		 curr_arc.to_d == target_a ) {
		removed_arcs.add(curr_arc);
	    }
	}

	// remove all arcs connected to this vertex
	//
	for (int i=0; i<removed_arcs.size(); i++) {
	    GraphArc curr_arc = (GraphArc)removed_arcs.get(i);
	    arcs_d.remove(curr_arc);
	}

	// reset the vertex focus
	//
	vertices_d.remove(target_a);
	CData.work_area_d.remove(target_a);

    }
  
    /**
     * store the digraph into a file
     * 
     * @param prefix_a the prefix of the property name
     */
    public void store(String prefix_a) {

	// get the io to set properties
	//
	Properties io = CData.io_d;
	
	// set the size of vertices and arcs
	//
	String vertex_size_name = prefix_a + CData.IO_IHD_VERTEX_SIZE;
	String arc_size_name = prefix_a + CData.IO_IHD_ARC_SIZE;

	String vertex_size = String.valueOf(vertices_d.size());
	String arc_size = String.valueOf(arcs_d.size());
	
	// write the size to the properties
	//
	io.setProperty(vertex_size_name, vertex_size);
	io.setProperty(arc_size_name, arc_size);
	
	// write all vertices
	//
	for (int i= 0; i < vertices_d.size(); i++) {
	    Vertex curr_vertex = (Vertex)vertices_d.get(i);
	    String prefix = prefix_a + CData.IO_VERTEX_PREFIX 
		+ String.valueOf(i);
	    curr_vertex.store(prefix);
	}

	// write all arcs
	//
	for (int i=0; i < arcs_d.size(); i++) {
	    GraphArc curr_arc = (GraphArc)arcs_d.get(i);
	    String prefix = prefix_a + CData.IO_ARC_PREFIX 
		+ String.valueOf(i);
	    curr_arc.store(prefix, this);
	}
    }

    /**
     * load the digraph from a file
     * 
     * @param prefix_a the prefix of the property name
     */
    public void load(String prefix_a) {

	// get the io to set properties
	//
	Properties io = CData.io_d;
	
	// set the size of vertices and arcs
	//
	String vertex_size_name = prefix_a + CData.IO_IHD_VERTEX_SIZE;
	String arc_size_name = prefix_a + CData.IO_IHD_ARC_SIZE;

	String vertex_size = io.getProperty(vertex_size_name, "0");
	String arc_size    = io.getProperty(arc_size_name, "0");
	int v_size = Integer.valueOf(vertex_size).intValue();
	int a_size = Integer.valueOf(arc_size).intValue();

	// load all vertices
	//
	for (int i= 0; i < v_size; i++) {
	    String prefix = prefix_a + CData.IO_VERTEX_PREFIX 
		+ String.valueOf(i);
	    Vertex curr_vertex = new Vertex();
	    curr_vertex.load(prefix);
	    vertices_d.add(curr_vertex);
	}

	// load all arcs
	//
	for (int i=0; i < a_size; i++) {
	    String prefix = prefix_a + CData.IO_ARC_PREFIX 
		+ String.valueOf(i);
	    GraphArc curr_arc = new GraphArc();
	    curr_arc.load(prefix, this);
	    insertArc( curr_arc);
	    //arcs_d.add( curr_arc );
	}
    }
  
}





