// DirectedVertex.java
// Copyright (C) 2000 Linyuan Lu
// Code based on David Binger's Vertex.java 
// Copyright (C) 1997 David Binger
// 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 PURPOSE.  See the
// GNU General Public License for more details.

// You should have received 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.

// Version 0.1

import java.awt.*;
import java.io.*;

public class DirectedVertex
extends Selectable
implements Serializable
{

    public int loop=1;
  // edges is a list of edges that touch this vertex.
  public List inedges = new List();
  public List outedges= new List();

  // position gives the coordinates of the center of the vertex.
  public Position position;

  // Vertices are drawn as circles or else as disks, depending on this flag.
  public boolean solid = true;
  
    public int inDegree(){ 
	int sum=loop;
	int n=inedges.length;
	Object a[]=inedges.elements;
	for(int i=0;i<n;i++){
	    sum+=((DirectedEdge) a[i]).multi;
	}
	return sum;
    }

   public int outDegree(){
       int sum=loop;
       int n=outedges.length;
       Object a[]=outedges.elements;
	for(int i=0;i<n;i++){
	   sum+=((DirectedEdge) a[i]).multi;
	}
	return sum;
    }
  // Serializable
  private void writeObject(ObjectOutputStream out)
  throws IOException {
    out.writeObject(inedges);
    out.writeObject(outedges);
    out.writeObject(position);
    out.writeBoolean(solid);
    out.writeInt(loop);
  }

  // Serializable
  private void readObject(ObjectInputStream in)
  throws IOException, ClassNotFoundException {
    inedges = (List)in.readObject();
    outedges = (List)in.readObject();
    position = (Position)in.readObject();
    solid = in.readBoolean();
    loop= in.readInt();
  }

  DirectedVertex(int x,int y) {
    position = new Position(x,y);
    defaultLabel();
  }
    
  DirectedVertex() {
    position = new Position(0,0);
    defaultLabel();
  }  

  public final void alter() {
    solid = !solid;
    defaultLabel();
  }
  
  public final void move(int x,int y) {
    position.x = x;
    position.y = y;
    defaultLabel();
    int n = inedges.length;
    Object a[] = inedges.elements;
    for (int j=0;j<n;j++) {
	DirectedEdge et=((DirectedEdge)a[j]);
        et.revalidate();
        et.defaultLabel();
    }
    n = outedges.length;
    a = outedges.elements;
    for (int j=0;j<n;j++) {
	DirectedEdge et=((DirectedEdge)a[j]);
        et.revalidate();
        et.defaultLabel();
    }
  }

  // How far is x,y from the center of the disk?
  public final double distance(double x,double y) {
    double a = x-position.x;
    double b = y-position.y;
    return Math.sqrt(a*a+b*b);
  }
  
  // Is the point a,b inside this disk?
  public final boolean hitDisk(int a,int b) {
    int x = position.x();
    if ((a<x-size) || (a>x+size)) return false;
    int y = position.y();
    if ((b<y-size) || (b>y+size)) return false;
    int c = x-a;
    int d = y-b;
    if ((c*c+d*d)>(size*size)) return false;
    return true;
  }

  public final void adjustSize(int d) {
    int r = size + d;
    if (r>=0) size = r;
    defaultLabel();
  }

  // Place the label to the right of the disk, if it is solid,
  // and centered in the disk if it is not solid.
  public final void defaultLabel() {
    int x = position.x();
    int y = position.y();
    if (solid) moveLabel(x+size+2,y);
    else {
      moveLabel(x,y);
      validateLabelBounds();
      if (labelBounds.width>2) {
	x -= (labelBounds.width-1)/2-1;
	y += (labelBounds.height-1)/2-1;
	moveLabel(x,y);
      }
    }
  }    
    
  public final void paintDisk(Graphics g) {
    if (size<=0) return;
    int x = position.x();
    int y = position.y();
    int side = 2*size+2;
    g.setColor(getColor(color));
    if (solid) {
      g.fillArc(x-size,y-size,side,side,0,360);
    }
    else {
      g.setColor(Color.white);
      g.fillArc(x-size,y-size,side,side,0,360);
      g.setColor(getColor(color));
      side--;
      g.drawArc(x-size,y-size,side,side,0,360);
    }
  }
  
  public final void paint(Graphics g) {
    paintDisk(g);
  }

  public final void addInEdge(DirectedEdge e) {
      for(int i=0;i<inedges.length;i++){
	  DirectedEdge et=inEdge(i);
	  if(e.start.equals(et.start)){
	      et.multi+=e.multi;
	      et.length=-1;
	       e.length = -1;
	      //  System.out.println("I am here."+e);
	      return;
	  }
      }
      inedges.push(e); 
           e.length = -1;
  }

  public final void addOutEdge(DirectedEdge e) {
      for(int i=0;i<outedges.length;i++){ 
	  DirectedEdge et=outEdge(i);
	  if(e.end.equals(et.end)){
	      et.multi+=e.multi;
	      et.length=-1;
	       e.length = -1;
	      //  System.out.println("I am here."+e);
	      return;
	  }
      } 
    outedges.push(e);
          e.length = -1;
  }


  public final void delInEdge(DirectedEdge e) {
      for(int i=0;i<inedges.length;i++){
	 DirectedEdge et=inEdge(i);
	  if(e.start.equals(et.start)){
	    et.multi-=e.multi;
	  if(et.multi<=0) 
              inedges.delete(et);
	  }
      }
  }

 public final void delOutEdge(DirectedEdge e) {
      for(int i=0;i<outedges.length;i++){
	  DirectedEdge et=outEdge(i);
	  if(e.end.equals(et.end)){
	    et.multi-=e.multi;
	  if(et.multi<=0) 
              outedges.delete(et);
	  }
      }
  }

  public final DirectedEdge inEdge(int p) {
    return ((DirectedEdge)inedges.elements[p]);
  }

   public final DirectedEdge outEdge(int p) {
    return ((DirectedEdge)outedges.elements[p]);
  }
  
  public final void moveRelative(double a,double b) {
    int x = (int)a;
    int y = (int)b;
    moveLabelRelative(x,y);
    position.x+=x;
    position.y+=y;
  }
  
  public String toString() {
    String s = "(Vertex ";
    s += String.valueOf(hashCode());
    s += " "+position;
    s += " "+solid;
    s += " " + super.toString() + " ";
    s += " )";
    return s;
  }

}











