#include "MaskParameterisation.hh"
#include "G4SystemOfUnits.hh"
#include "G4PhysicalConstants.hh"

#include "G4VPhysicalVolume.hh"
#include "G4ThreeVector.hh"
#include "G4RotationMatrix.hh"
#include "G4Box.hh"

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>


MaskParameterisation::MaskParameterisation(G4double side_length_X, G4double side_length_Y, G4int n_side, G4double gap, const std::string& filename)
    : fSideX(side_length_X), fSideY(side_length_Y), nSide(n_side), fGap(gap) 
{
    // Carica zeroPositions dal file
    int totalZeros = LoadZeroPositions(filename);
    if (totalZeros == -1) {
        G4cerr << "Errore durante il caricamento del file " << filename << G4endl;
    }
}


MaskParameterisation::~MaskParameterisation() 
{;}


int MaskParameterisation::LoadZeroPositions(const std::string& filename)
{
    std::ifstream infile(filename);  //apre il file in modalità lettura
    if (!infile) {
        std::cerr << "Errore nell'apertura del file " << filename << std::endl;
        return -1;
    }

    std::string line; //memorizza la riga corrente del file
    int rowID = 0;
    int totalZeros = 0;

    // Leggi il file riga per riga
    while (std::getline(infile, line)) { // legge il file una riga alla volta. std::getline carica il contenuto della riga corrente in line
        // Salta le righe commentate
        if (line[0] == '#') continue;

        std::istringstream iss(line);  // crea uno stream di input (iss) dalla riga letta (line), per processare ogni elemento della riga come valore numerico
        int colID = 0;
        int value;   // value memorizza ciascun numero estratto dalla riga.

        // Leggi ogni numero della riga e controlla se è uno zero
        while (iss >> value) {  // >> estrae il prossimo elemento dallo stream iss e lo assegna a value.
            if (value == 0) {  // Se l'operazione ha successo (ossia se iss ha ancora un numero da leggere), il ciclo while continua; altrimenti, iss >> value restituisce false, terminando il ciclo while
                // Aggiungi la posizione (rowID, colID) all'array zeroPositions
                zeroPositions.push_back(std::make_pair(rowID, colID));
                totalZeros++;
            }
            colID++;
        }
        rowID++;
    }

    infile.close();
    return totalZeros;
}

int MaskParameterisation::GetTotalZeros() const 
{
    return zeroPositions.size();  // Ritorna il numero totale di zeri, che corrisponde alla dimensione del vettore zeroPositions
}


void MaskParameterisation::ComputeTransformation (const G4int copyNo, G4VPhysicalVolume* physVol) const
{
    G4double xCell = 0.*cm;
    G4double yCell = 0.*cm;
    G4double zCell = 0.*cm;

    int rowID = zeroPositions[copyNo].first;
    int colID = zeroPositions[copyNo].second;

    xCell = (fSideX) *((-nSide+1)/2 + colID);  // potrei scrivere fSideX+fGap se voglio aggiungere il gap
    yCell = (fSideY) *((-nSide+1)/2 + rowID); 

    physVol->SetTranslation(G4ThreeVector(xCell, yCell, zCell)); 

    // G4cout << "*** DEBUG copyNo " << copyNo << " rowID " << rowID << " colID " << colID << G4endl;
    // G4cout << "*** DEBUG xCell " << xCell/cm << " yCell " << yCell/cm << G4endl;    
    
}




// ! OLD MASK
// void MaskParameterisation::ComputeTransformation (const G4int copyNo, G4VPhysicalVolume* physVol) const
// {
//     G4double xCell = 0.*cm;
//     G4double yCell = 0.*cm;
//     G4double zCell = 0.*cm;

//     if (nSide % 2 == 0) // Even number of tiles per side
//     {
//         G4int rowID = copyNo / nSide;                                   // identifies the row of the tile
//         G4int colID = (copyNo % nSide)*2 + (((int) copyNo/nSide)%2);    // in order to have tiles in odd-numbered rows shifted by one column w.r.t. the adjacent rows
// //        G4cout << "*** DEBUG copyNo " << copyNo << " rowID " << rowID << " colID " << colID << G4endl;
//         xCell = (2*colID - (2*nSide -1)) *fSideX/2;
//         yCell = (2*rowID - (2*nSide -1)) *fSideY/2;
// //        G4cout << "*** DEBUG xCell " << xCell/cm << " yCell " << yCell/cm << G4endl;
// //        G4cout << " " << G4endl;
//     }
    
//     physVol->SetTranslation(G4ThreeVector(xCell, yCell, zCell));
    
// }
