/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: CellPrinter.java
 * Written by: Christian Julg, Jonas Thedering (Team 1)
 *
 * Copyright (c) 2010, Static Free Software. All rights reserved.
 *
 * Electric(tm) 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 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) 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, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.routing.experimentalAStar1;

import java.util.List;

import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.tool.routing.RoutingFrame.RoutingContact;
import com.sun.electric.tool.routing.RoutingFrame.RoutingGeometry;
import com.sun.electric.tool.routing.RoutingFrame.RoutingLayer;
import com.sun.electric.tool.routing.RoutingFrame.RoutingSegment;

/* Prints debug information about the cell to be routed */
public class CellPrinter {

	public static void printLayers(List<RoutingLayer> allLayers) {
		for (RoutingLayer layer : allLayers) {
			System.out.printf("Layer: %s, metal:%b\n", layer.getName(), layer
					.isMetal());
			RoutingContact pin = layer.getPin();
			if (pin != null) {
			System.out.printf("Pin: %s, firstLayer:%s, secondLayer:%s\n", pin
					.getName(), pin.getFirstLayer().getName(), pin
					.getSecondLayer().getName());
			}
		}
	}

	public static void printContacts(List<RoutingContact> allContacts) {
		for (RoutingContact contact : allContacts) {

			double viaSpacing = contact.getViaSpacing();

			System.out.printf("Contact: %s, firstLayer:%s, secondLayer:%s, viaSpacing=%f\n",
					contact.getName(), contact.getFirstLayer().getName(),
					contact.getSecondLayer().getName(), viaSpacing);
		}
	}

	public static void printChipStatistics(Cell cell, List<RoutingSegment> segmentsToRoute, List<RoutingLayer> allLayers,
			List<RoutingContact> allContacts, List<RoutingGeometry> blockages) {
		
		int metalLayers = 0;
		
		for(RoutingLayer rl : allLayers) {
			if(rl.isMetal()) {
				metalLayers++;
			}
		}
		
		int[] layerDistance = new int[metalLayers];
		int[] layerMembership = new int[metalLayers];
		int[][] crossLayerMembership = new int[metalLayers][metalLayers]; 
		int singleLayer = 0;
		int crossLayer = 0;
		
		int maxNetID = Integer.MIN_VALUE;
		
		for(RoutingSegment rs : segmentsToRoute) {
			maxNetID = Math.max(maxNetID, rs.getNetID());
			
			int minStart = Integer.MAX_VALUE;
			int maxStart = Integer.MIN_VALUE;
			for(RoutingLayer rl : rs.getStartLayers()) {
				minStart = Math.min(minStart, rl.getMetalNumber());
				maxStart = Math.max(maxStart, rl.getMetalNumber());
			}
			int minFinish = Integer.MAX_VALUE;
			int maxFinish = Integer.MIN_VALUE;
			for(RoutingLayer rl : rs.getFinishLayers()) {
				minFinish = Math.min(minFinish, rl.getMetalNumber());
				maxFinish = Math.max(maxFinish, rl.getMetalNumber());
			}
			
			if(minStart==maxStart && minFinish==maxFinish) {
				int distance = Math.abs(minStart-minFinish);
				layerDistance[distance]++;
				if(minStart == minFinish) {
					singleLayer++;
					layerMembership[minStart-1]++;
				}
				else {
					// XXX: appears not to work as expected
					int min = Math.min(minStart, minFinish);
					int max = Math.max(minStart, minFinish);
					crossLayerMembership[min-1][max-1]++;
					crossLayer++;
				}
			}
		}
		
		int[] nets = new int[maxNetID+1];
		
		for(RoutingSegment rs : segmentsToRoute) {
			nets[rs.getNetID()]++;
		}
		
		int numberOfNets = 0;
		int maxSegments = Integer.MIN_VALUE;
		
		for(int i=0; i<nets.length; i++) {
			if(nets[i] != 0) {
				numberOfNets++;
			}
			maxSegments = Math.max(maxSegments, nets[i]);
		}
		
		int[] numberOfSegments = new int[maxSegments];
		for(int i=0; i<nets.length; i++) {
			if(nets[i] != 0) {
				numberOfSegments[nets[i]-1]++;
			}
		}
		
		int[] blockagesOnLayer = new int[metalLayers];
		
		for(RoutingGeometry rg : blockages) {
			blockagesOnLayer[rg.getLayer().getMetalNumber()-1]++;
		}
		
		System.out.println();
		System.out.println();
		System.out.print("#Metal-Layers: " + metalLayers + " { ");
		for(RoutingLayer rl : allLayers) {
			if(rl.isMetal()) {
				System.out.print(rl.getMetalNumber() + ", ");
			}
		}
		System.out.println("}\n");
		
		System.out.println("#Segments: " + segmentsToRoute.size());
		System.out.println("\t on one layer:  " + singleLayer);
		for(int i=0; i<layerMembership.length; i++) {
			if(layerMembership[i] != 0) {
				System.out.println("\t\t Metal-" + (i+1) + ": " + layerMembership[i]);
			}
		}
		System.out.println("\t on two layers: " + crossLayer);
		for(int i=0; i<crossLayerMembership.length; i++) {
			for(int j=0; j<crossLayerMembership[0].length; j++) {
				if(crossLayerMembership[i][j] != 0) {
					System.out.println("\t\t Metal-" +(i+1)+ " - Metal-" + (j+1) + ": " + crossLayerMembership[i][j]);
				}
			}
		}
		System.out.println();
		
		System.out.println("layer distance distribution");
		for(int i=0; i<layerDistance.length; i++) {
			if(layerDistance[i] != 0) {
				System.out.println("\t distance " + i + ": " + layerDistance[i]);
			}
		}
		System.out.println();

		System.out.println("#Blockages: " + blockages.size());
		for(int i=0; i<blockagesOnLayer.length; i++) {
			if(blockagesOnLayer[i] != 0) {
				System.out.println("\t on Metal-" + (i+1) + ": " + blockagesOnLayer[i]);
			}
		}
		System.out.println();
		
		int countNumSegments = 0;
		
		System.out.println("#Nets: " + numberOfNets);
		for(int i=0; i<numberOfSegments.length; i++) {
			if(numberOfSegments[i] != 0) {
				countNumSegments += numberOfSegments[i] * (i+1); 
				System.out.print("\t " +(i+1) + " segments: " + numberOfSegments[i] + "{ ");
				for(int j=0; j<nets.length; j++) {
					if(nets[j] == (i+1)) {
						System.out.print(j + ", ");
					}
				}
				System.out.println("}");
			}
		}
		System.out.println("\tsum: " + countNumSegments + " segments");
		

	}
}
