<?php
class Bbvaservice 
{
    protected   $SECUENCIA_IMPORTE = [1,3,7];
    protected   $MULTIPLICADOR_FECHA_JULIANA_MES = 31;
    protected   $MULTIPLICADOR_FECHA_JULIANA_ANIO = 372;
    protected   $SUSTRAENDO_FECHA_JULIANA_ANIO = 2014;
    protected   $DIGITO_DE_CONTROL = 2;
    protected   $TABLA_EQUIVALENCIAS = [
        "A" => 1, "B" => 2, "C" => 3, "D" => 4,
        "E" => 5, "F" => 6, "G" => 7, "H" => 8,
        "I" => 9, "J" => 1, "K" => 2, "L" => 3,
        "M" => 4, "N" => 5, "O" => 6, "P" => 7,
        "Q" => 8, "R" => 9, "S" => 2, "T" => 3,
        "U" => 4, "V" => 5, "W" => 6, "X" => 7,
        "Y" => 8, "Z" => 9
    ];
    protected   $SECUENCIA_LINEA_CAPTURA = [23,19,17,13,11];

    public function generaLineaDeCaptura( $plantel, $matricula, $clave_concepto, $importe, $fecha )
    {
        $this->plantel = $plantel;
        $this->matricula = $matricula;
        $this->importe = $importe;
        $this->fecha = $fecha;
        $this->clave_concepto = $clave_concepto;

        $referencia = $this->plantel . $this->matricula . $this->clave_concepto ;
        $digito_verificador_importe = $this->digitoVerificadorImporte( $this->importe );
        $fecha_juliana = $this->calculaFechaJuliana( $this->fecha );        
        $linea_de_captura = $referencia . $fecha_juliana . $digito_verificador_importe . $this->DIGITO_DE_CONTROL;
        $digito_verificador_linea = $this->calculaDigitoVerificadorLineaCaptura( $linea_de_captura );
        $linea_de_captura = $linea_de_captura . $digito_verificador_linea;
        return $linea_de_captura;
    }

    private function digitoVerificadorImporte( $importe )
    {
        $importe = number_format($importe, 2, ".", "");
        $importe = str_replace( ".", "", $importe );
        //Paso 1 - Asignar a cada digito el valor 7,3,1, de izquierda a derecha
        $pointer = 2;
        $importe_array = str_split( $importe );
        $valores_asignados_array = [];
        $valores_importe_array = [];
        $valores_multiplicados_array = [];
        for( $i = sizeof( $importe_array ); $i > 0 ; $i-- )
        {
            $index = $i - 1;            
            $valores_importe_array[] = $importe_array[$index];
            $valores_asignados_array[] = $this->SECUENCIA_IMPORTE[$pointer];
            $pointer--;            
            if( $pointer == -1)
            {
                $pointer = 2;
            }
        }

        //Paso 2 - Multiplicar cada digito del importe por el valor que corresponda
        for( $i = 0;  $i < sizeof( $valores_importe_array ); $i++ )
        {
            $valor = $valores_importe_array[$i] * $valores_asignados_array[$i];
            $valores_multiplicados_array[] = $valor;
        }

        //Paso 3 - Se suman los valores multiplicados en el paso 2
        $resultado = 0;
        for( $i = 0; $i < sizeof($valores_multiplicados_array); $i++)
        {
            $resultado += $valores_multiplicados_array[$i];
        }

        //Paso 4 - Del resultado de la suma se obtiene el módulo
        $digito_verificador_importe = $resultado % 10;

        return $digito_verificador_importe;

    }

    private function calculaFechaJuliana( $fecha )
    {
        $elementos_fecha =  explode("-", $fecha);
        $dia =  intval($elementos_fecha[2]);
        $mes =  intval($elementos_fecha[1]);
        $anio = intval($elementos_fecha[0]);

        //Paso 1 - Tomamos el dia y le restamos el valor 1
        $dia = $dia - 1;

        //Paso 2 - Tomamos el mes, le restamos el valor 1 y lo multiplicamos por 31
        $mes = ( $mes - 1 ) * $this->MULTIPLICADOR_FECHA_JULIANA_MES;

        //Paso 3 - Tomamos el año, le restamos el valor 2013 y lo multiplicamos por 372
        $anio = ( $anio - $this->SUSTRAENDO_FECHA_JULIANA_ANIO ) * $this->MULTIPLICADOR_FECHA_JULIANA_ANIO;

        //Paso 4 - Sumamos los 3 elementos anteriores y obtendremos la fecha Juliana
        $fecha_juliana = $dia + $mes + $anio;

        //Paso 5 - Ajustamos la fecha juliana a 4 posiciones
        $fecha_juliana = str_pad( $fecha_juliana, 4, "0", STR_PAD_LEFT );

        return $fecha_juliana;        
    }

    private function calculaDigitoVerificadorLineaCaptura( $linea_de_captura )
    {
        //Paso 1 - Convertimos los caracteres a numeros de acuerdo a la tabla Modulo 11
        $referencia_array = str_split( $linea_de_captura );
        $valores_referencia_array = [];
        for( $i = 0; $i < sizeof( $referencia_array); $i++ )
        {
            $valor = $referencia_array[$i];
            if( array_key_exists($valor, $this->TABLA_EQUIVALENCIAS ) )
            {
                $valores_referencia_array[] = $this->TABLA_EQUIVALENCIAS[ $valor ]; 
            }
            else 
            {
                $valores_referencia_array[] = $valor;
            }
        }
        
        //Paso 2 - Asignar a cada digito el valor 11,13,17,19,23 de izquierda a derecha
        $pointer = 4;
        $valores_asignados_array = [];
        for( $i = sizeof( $valores_referencia_array ); $i > 0 ; $i-- )
        {
            $valores_asignados_array[] = $this->SECUENCIA_LINEA_CAPTURA[$pointer];
            $pointer--;
            if( $pointer == -1)
            {
                $pointer = 4;
            }
        }

        //Paso 3 - Multiplicar cada digito por el valor que corresponda
        $valores_multiplicados_array = [];
        $pointer_valores = sizeof($valores_asignados_array) - 1;
        for( $i = 0; $i < sizeof($valores_asignados_array); $i++ )
        {
            $valores_multiplicados_array[] = $valores_asignados_array[$i] * $valores_referencia_array[$pointer_valores];
            $pointer_valores--;
        }

        //Paso 4 - Sumar el resultado de cada multiplicacion
        $resultado = 0;
        for( $i = 0; $i < sizeof($valores_multiplicados_array); $i++ )
        {
            $resultado += $valores_multiplicados_array[$i];            
        }

        //Paso 5 - El resultado se divide entre 97 y al residuo se le suma el valor 1
        $digito_verificador_linea = ( $resultado % 97 ) + 1;

        //Paso 6 - Ajustamos el digito verificador 2 posiciones
        $digito_verificador_linea = str_pad( $digito_verificador_linea, 2, "0", STR_PAD_LEFT );
        
        return $digito_verificador_linea;
    }    
}
?>