#include <G4UIdirectory.hh>
#include <G4UIcmdWithABool.hh>
#include <G4UIcmdWithAString.hh>
#include <G4Material.hh>
#include <G4VPhysicalVolume.hh>
#include <G4LogicalVolume.hh>
#include <G4VSolid.hh>
#include <G4OpticalSurface.hh>

#include <RAT/DetectorMessenger.hh>
#include <RAT/Detector.hh>
#include <RAT/Surfaces.hh>
#include <RAT/Log.hh>
using namespace RAT;

DetectorMessenger::DetectorMessenger( Detector* detector )
  :fDetector( detector )
{
  fDetectorDir = new G4UIdirectory( "/rat/detector/" );
  fDetectorDir->SetGuidance( "Detector commands" );

  fMaterialCmd = new G4UIcmdWithAString( "/rat/detector/dump_material", this );
  fMaterialCmd->SetGuidance( "Output a material's properties" );
  fMaterialCmd->SetParameterName( "MaterialName", false ); // false==Required
  fMaterialCmd->AvailableForStates( G4State_PreInit, G4State_Init, G4State_Idle );

  fGeometryCmd = new G4UIcmdWithAString( "/rat/detector/dump_geometry", this );
  fGeometryCmd->SetGuidance( "Output a geometry volume's properties" );
  fGeometryCmd->SetParameterName( "GeometryName", false ); // false==Required
  fGeometryCmd->AvailableForStates( G4State_PreInit, G4State_Init, G4State_Idle );

  fSurfaceCmd = new G4UIcmdWithAString( "/rat/detector/dump_surface", this );
  fSurfaceCmd->SetGuidance( "Output a surface's properties" );
  fSurfaceCmd->SetParameterName( "SurfaceName", false ); // false==Required
  fSurfaceCmd->AvailableForStates( G4State_PreInit, G4State_Init, G4State_Idle );

  fCheckOverlapsCmd =  new G4UIcmdWithABool( "/rat/detector/check_overlaps", this );
  fCheckOverlapsCmd->SetGuidance( "Will force overlap checking when building the geometry" );
  fCheckOverlapsCmd->SetParameterName( "CheckOverlaps", false ); // false==Required
  fCheckOverlapsCmd->AvailableForStates( G4State_PreInit );
}

DetectorMessenger::~DetectorMessenger()
{
  delete fMaterialCmd;
  delete fGeometryCmd;
  delete fSurfaceCmd;
  delete fCheckOverlapsCmd;
  delete fDetectorDir;
}

void
DetectorMessenger::SetNewValue( G4UIcommand* command,
                                G4String newValue )
{
  if( command == fMaterialCmd )
    {
      if( newValue == "" )
        G4cout << *(G4Material::GetMaterialTable()) << newline; // conversion is only to G4cout
      else
        {
          G4Material* material = G4Material::GetMaterial( newValue );
          if( material == NULL )
            Log::Die( "DetectorMessenger::SetNewValue: material doesn't exist" );
          G4cout << *material << newline; // conversion is only to G4cout
          G4MaterialPropertiesTable* properties = material->GetMaterialPropertiesTable();
          if( properties != NULL )
            properties->DumpTable();
        }
    }
  else if( command == fGeometryCmd )
    {
      if( newValue == "" )
        newValue = "world";
      G4VPhysicalVolume* volume = Detector::FindPhysicalVolume( newValue );
      if( volume == NULL )
        Log::Die( "DetectorMessenger::SetNewValue: Geometric volume doesn't exist" );
      else
        {
          info << "Physical Volume name " << volume->GetName() << newline;
          G4LogicalVolume* logical = volume->GetLogicalVolume();
          info << " Logical volume name: " << logical->GetName() << newline;
          info << " Solid name: " << logical->GetSolid()->GetName() << newline;

          G4Material* material = logical->GetMaterial();
          info << " Material: " << material->GetName() << newline;

          info << " Daughters: " << newline;
          for( int i = 0; i < logical->GetNoDaughters(); i++ )
            info << "\t" << logical->GetDaughter( i )->GetName() << newline;
        }
    }
  else if( command == fSurfaceCmd )
    Surfaces::GetSurface( newValue )->DumpInfo();
  else if( command == fCheckOverlapsCmd )
    fDetector->SetCheckOverlaps( fCheckOverlapsCmd->GetNewBoolValue( newValue ) );
  else
    Log::Die( "DetectorMessenger::SetNewValue: ERROR > Invalid DetectorMessenger command " );
}