#include "Report.h"

namespace cosi {

namespace io {

namespace onchipcommunication {

using namespace std ;

void PrintReport( string pFileName , ProjectParser* pPrj , cosi::platforms::onchipcommunication::NocPlatformInterface* pPlt ,  cosi::algorithms::onchipcommunication::NetworkCost* pCost ) {

  //----------------------------------------------------------
  //                Open File
  //----------------------------------------------------------

  ofstream f ;
  f.open( pFileName.c_str( ) ) ;

  f<< "Generated by COSI OCC 1.3 " << endl ;
  f<< endl ;
  // TODO : add the date when this report was generated
  f<< "Report for project " << pPrj->GetProjectName( ) << endl << endl ;


  //----------------------------------------------------------
  //        Write some interesting technology parameters
  //----------------------------------------------------------
  f << "  " << "Library file  " << pPrj->GetLibraryFileName( )  << endl ;
  f << "  " << "Library  " << pPrj->GetLibraryName( ) << endl ;
  f << "  " << "Fclk  " << pPlt->OperatingFrequency( ) << endl ;
  f << "  " << "Critical sequential length (Lst) " << pPlt->WireLst( )*1e3 << " mm" <<  endl ;
  //f << "  " << "Optimal buffer size " << pPlt->Kopt( ) << "  " <<  "Critical sequential length (Lst) " << pPlt->WireLst( )*1e3 << " mm" <<  endl ;
  f << "  " << "Dynamic energy per unit length per bit " << pPlt->WireEnergy( )*1e12 << " pJ" << endl ;
  f << "  " << "Leaakge power per unit length per bit " << pPlt->WireLeakage( )*1e9 << " nW" << endl ;
  f << "  " << "Wire pitch for global wires  " << pPlt->WirePitch( )*1e9 << " nm" << endl ;
  f << "  " << "Flit width  " << pPlt->FlitWidth( ) << " bits" << endl ;
  f << "  " << "Dynamic energy per flit of a " << pPlt->MaxInDegree( ) << "x" << pPlt->MaxOutDegree( ) << " router  " << pPlt->RouterEnergy( pPlt->MaxInDegree() , pPlt->MaxOutDegree( ) )*1e12 << " pJ" << endl ;
  f << "  " << "Area of a " << pPlt->MaxInDegree( ) << "x" << pPlt->MaxOutDegree( ) << " router  " << pPlt->RouterArea( pPlt->MaxInDegree() , pPlt->MaxOutDegree( ) )*1e12  << " um^2" << endl ;

  f << endl ;

  //----------------------------------------------------------
  //                Write synthesis constraints
  //----------------------------------------------------------
  f << "Synthesis constraints " << endl ;
  f << "  " << "Spare area during floorplannig  " << pPrj->GetSpareArea( ) << " \% of block area" << endl ;
  f << "  " << "Step size  " << pPrj->GetStep( ) << " of Lst " << endl ;
  f << "  " << "Source maximum output degree  " << pPlt->SourceOutDegree( ) << endl ;
  f << "  " << "Destination maximum input degree  " << pPlt->DestInDegree( ) << endl ;
  f << "  " << "Rotuer maximum input degree  " << pPlt->MaxInDegree( ) << endl ;
  f << "  " << "Router maximum output degree  " << pPlt->MaxOutDegree( ) << endl ;
  f << "  " << "Switching activity  " << pPlt->SwitchingFactor( ) << endl ;
  f << "  " << "Relative power vs. area cost  " << pPlt->PowerVsArea( ) << endl ;
//  f << "  " << "Allow point-to-point connections ?  " ;
//  if ( pPlt->AllowPtP() )
//    f << "Yes" << endl ;
//  else
//    f << "No" << endl ;

  f << endl ;

  //----------------------------------------------------------
  //                Write network costs and performances
  //----------------------------------------------------------
  f << "Power report " << endl ;
  f << "  " << "Wires : " << endl;
  f << "    " << "Dynamic power = " << pCost->GetWireDynamicPower( ) << " W" << endl ;
  f << "    " << "Static  power = " << pCost->GetWireStaticPower( ) << " W"<< endl ;
  f << "    " << "Total   power = " << pCost->GetWireTotalPower( ) << " W"<< endl ;
  f << "  " << "Routers : " << endl;
  f << "    " << "Dynamic power = " << pCost->GetRouterDynamicPower( ) << " W"<< endl ;
  f << "    " << "Static  power = " << pCost->GetRouterStaticPower( ) << " W"<< endl ;
  f << "    " << "Total   power = " << pCost->GetRouterTotalPower( ) << " W"<< endl ;
//  f << "  " << "Interfaces : " << endl ;
//  f << "    " << "Total   power = " << pCost->GetInterfacePower( ) << " W" << endl ;
  f << "    " << "                ---------------------" << endl ;
  f << "  " <<   "Network dynamic power =   " <<  pCost->GetRouterDynamicPower( ) + pCost->GetWireDynamicPower( ) << endl;
  f << "  " <<   "Network power =   " <<  pCost->GetRouterTotalPower( ) + pCost->GetWireTotalPower( )  << endl;


  f << endl ;
  f << "Area report " << endl ;
  //f << "Chip dimensions " << pPlt->GetChipW( )*1e3 << "x" << pPlt->GetChipH( )*1e3 << " mm^2" << endl ;
  f << "  " << "Wires : " << endl;
  f << "    " << "Minimum length  " << pCost->GetMinDist( )*1e3 << " mm" << endl;
  f << "    " << "Maximum length  " << pCost->GetMaxDist( )*1e3 << " mm" << endl;
  f << "    " << "Total length  " << pCost->GetTotalDist( )*1e3 << " mm" << endl;
  f << "    " << "Average length  " << pCost->GetAverageDist( )*1e3 << " mm" << endl;
  f << "    " << "Wiring Area  " << pCost->GetWireWiringArea()*1e6 << " mm^2" << endl ;
  f << "    " << "Device Area  " << pCost->GetWireDeviceArea()*1e6 << " mm^2" << endl ;
  f << "    " << "Total Area   = " << pCost->GetWireArea( )*1e6 << " mm^2" << endl ;
  f << "  " << "Routers : " << endl;
  f << "    " << "Minimum input degree  " << pCost->GetMinInDegree( ) << endl ;
  f << "    " << "Maximum input degree  " << pCost->GetMaxInDegree( ) << endl ;
  f << "    " << "Average input degree  " << pCost->GetAverageInDegree( ) << endl ;
  f << endl ;
  f << "    " << "Minimum output degree  " << pCost->GetMinOutDegree( ) << endl ;
  f << "    " << "Maximum output degree  " << pCost->GetMaxOutDegree( ) << endl ;
  f << "    " << "Average output degree  " << pCost->GetAverageOutDegree( ) << endl ;
  f << endl ;
  f << "    " << pCost->GetNnodes( ) << "  nodes"  << endl ;

  //f << "    " << pCost->GetNrouter( ) << "  routers and " << pCost->GetNlatch( ) << " latches " << endl ;
  f << "    " << "Total area   = " << pCost->GetRouterArea( )*1e6 << "  mm^2" << endl ;
  f << endl ;
//  f << "  " << "Interfaces : " << endl;
//  f << "    " << "Total area   = " << pCost->GetInterfaceArea( )*1e6 << "  mm^2" << endl ;
  f << "    " << "            --------------------" << endl ;
  f << "  " <<   "Network area =   " << ( pCost->GetWireArea( ) + pCost->GetRouterArea( ) ) *1e6 << "  mm^2" << endl  ;
  f<< endl ;

  f<< "Delay report " << endl;
  f<< "  " << "Minimum number of hops  " << pCost->GetMinHop( ) << endl ;
  f<< "  " << "Maximum number of hops  " << pCost->GetMaxHop( ) << endl ;
  f<< "  " << "Average number of hops  " << pCost->GetAverageHop( ) << endl ;
  f<< endl ;


//    f << "List of paths with delay violation " << endl ;
//    map< pair<int,int> , pair<int,int> > Paths = pCost->GetViolatedPaths( ) ;
//    map< pair<int,int> , pair<int,int> >::iterator PathIt ;
//    for( PathIt = Paths.begin( ) ; PathIt != Paths.end( ) ; PathIt++ ) {
//      int S , D , L , H ;
//      S = (PathIt->first).first ;
//      D = (PathIt->first).second ;
//      L = (PathIt->second).first ;
//      H = (PathIt->second).second ;
//      f << "   " << S << " to " << D << " T = " << L << "   H = " << H << endl ;
//    }


//  f << "Point-to-point estimated metrics:" << endl ;
//  f << "  " << "Power : " << pCost->GetPtpPower() << endl ;
//  f << "  " << "Area : " << pCost->GetPtpArea() << endl ;

  f.close( ) ;

}

void AppendRow( string pFileName , ProjectParser* pPrj , cosi::platforms::onchipcommunication::NocPlatformInterface* pPlt ,  cosi::algorithms::onchipcommunication::NetworkCost* pCost ) {

  //----------------------------------------------------------
  //                Open File
  //----------------------------------------------------------

  ofstream f ;
  f.open( pFileName.c_str( ) , fstream::app ) ;


  //PdynW PleakW PtotW PdynR PleakR PtotR Ptot

  f << pPrj->GetProjectName( ) << "\t" ;

  f << pCost->GetWireDynamicPower( ) << "\t" ;
  f << pCost->GetWireStaticPower( ) << "\t" ;
  f << pCost->GetWireTotalPower( ) << "\t" ;
  f << pCost->GetRouterDynamicPower( ) << "\t" ;
  f << pCost->GetRouterStaticPower( ) << "\t" ;
  f << pCost->GetRouterTotalPower( ) << "\t" ;
  f << pCost->GetRouterTotalPower( ) + pCost->GetWireTotalPower( ) << "\t" ;

  //Awiring Adevide AtotW AR Atot

  f <<pCost->GetWireWiringArea()*1e6 << "\t" ;
  f << pCost->GetWireDeviceArea()*1e6 << "\t" ;
  f <<  pCost->GetWireArea( )*1e6<< "\t" ;
  f <<pCost->GetRouterArea( )*1e6 << "\t" ;
  f <<( pCost->GetWireArea( ) + pCost->GetRouterArea( ) ) *1e6 << "\t" ;

  //Maxin Avgin Maxout Avgout

  f << pCost->GetMaxInDegree( ) << "\t" ;
  f << pCost->GetAverageInDegree( ) << "\t" ;
  f << pCost->GetMaxOutDegree( ) << "\t" ;
  f << pCost->GetAverageOutDegree( ) << "\t" ;
  //MaxHop AvgHop

  f<< pCost->GetMaxHop( ) << "\t" ;
  f<< pCost->GetAverageHop( ) << "\t" ;
  f<< endl ;

  //in2 in3... in10 out2 out3... out10

  f.close( ) ;

}
}
}
}
