<?php
defined('BASEPATH') or exit('No direct script access allowed');

require_once dirname(__FILE__) . "/../../metode/ExponentialSmoothing.php";

class Peramalan extends CI_Controller
{

    function __construct()
    {
        parent::__construct();
        $this->load->helper('url');
        $this->load->model('M_pelayanan');
        $this->load->model('M_pengunjung');

        if ($this->session->userdata('status') != "login") {
            redirect(base_url("Auth"));
        }
    }

    public function index()
    {
        $id_pelayanan = $this->input->get('id_pelayanan');
        $bulan = $this->input->get('bulan');
        $tahun = $this->input->get('tahun');
        $data['pelayanan'] = $this->M_pelayanan->get_all()->result();
        $data['alpha'] = $this->M_pelayanan->alpha()->row_array();

        if ($bulan != "" && $tahun != "") {
            $data['detail_pelayanan'] = $this->M_pelayanan->get_detail($id_pelayanan)->row_array();
            $ft = $this->get_peramalan($id_pelayanan, $bulan, $tahun);
            $data['data'] = $ft['hasilRamal'];
            $data['MAD'] = $ft['MAD'];
            $data['MSE'] = $ft['MSE'];
            $data['MAPE'] = $ft['MAPE'];
            $data['ratarataKesalahan'] = $ft['ratarataKesalahan'];
        } else {
            $data['detail_pelayanan'] = null;
            $data['data'] = [];
            $data['MAD'] = null;
            $data['MSE'] = null;
            $data['MAPE'] = null;
            $data['ratarataKesalahan'] = null;
        }

        $this->load->view('peramalan', $data);
    }

    public function update_alpha()
    {
        $alpha = $this->input->post('alpha');
        $beta = $this->input->post('beta');
        $gamma = $this->input->post('gamma');
        $data = array(
          'alpha' => $alpha,
          'beta' => $beta,
          'gamma' => $gamma
        );

        $where = array(
          'id_alpha' => '1'
        );
        $this->M_pelayanan->update($where, $data, 'alpha');
        
        $response['success'] = true;
        $response['message'] = "Alpha Berhasil Diubah !";     
        echo json_encode($response);
    }

    public function get_peramalan($id_pelayanan, $bulan, $tahun)
    {
        $hasilRamal = array();
        $awal = $this->M_pengunjung->tgl_kunjungan($id_pelayanan, 'asc')->row_array();
        $akhir = $this->M_pengunjung->tgl_kunjungan($id_pelayanan, 'desc')->row_array();

        $params = $this->M_pelayanan->alpha()->row_array();
        $alpha = $params['alpha'];
        $beta = $params['beta'];
        $gamma = $params['gamma'];
        $L = $params['periode'];

        $dataAktual = [];
        $blnRamal = $tahun . '-' . $bulan . '-01';
        $blnAwal = isset($awal['tanggal']) ? $awal['tanggal'] : date('Y-m-d');
        $blnAkhir = isset($akhir['tanggal']) ? $akhir['tanggal'] : date('Y-m-d');

        // mengambil data rekap pengunjung
        if ($id_pelayanan!="") {
          $srs = $this->M_pengunjung->get_rekap_pengunjung($id_pelayanan)->result_array();
        } else {
          $srs = $this->M_pengunjung->get_rekap_total_pengunjung()->result_array();
        }

        // Mengambil nilai data aktual
        foreach ($srs as $row) {
            $dataAktual[] = $row['jumlah'];
        }

        $starter = 0;
        $lb = 0;
        // generate list bulan dan jumlah data aktual, dari awal hingga akhir bulan kunjungan pada setiap pelayanan
        for ($t = date("Y", strtotime($blnAkhir)); $t <= date("Y", strtotime($blnRamal)); $t++) {
            if ($starter == 0) {
                $lb = date("m", strtotime($blnAkhir)) + 1;
            } else {
                $lb = 1;
            }

            for ($b = $lb; $b <= 13; $b++) {
                if ($b > 12) {
                    $starter = 1;
                    break;
                } else {

                    if ($t == date("Y", strtotime($blnRamal)) && $b > date("m", strtotime($blnRamal))) {
                        break;
                    } else {
                        // proses menambahkan / menggabungkan data series bulanan dengan bulan selanjutnya
                        $bulanStr = sprintf("%02d", $b) . "-" . $t;
                        $srs[] = array(
                            'bulan' => $bulanStr,
                            'jumlah' => null
                        );
                    }
                }
            }
        }

        // Jika data rekap pengunjung sebelumnya kosong maka akan mengembalikan nilai dengan data peramalan null
        if (count($dataAktual) == 0) {
            for ($i = 0; $i < count($srs); $i++) {
                $hasilRamal[] =  array(
                    'bulan' => $srs[$i]['bulan'],
                    'jumlah' => isset($srs[$i]['jumlah']) ? $srs[$i]['jumlah'] : 0,
                    'lt' => null,
                    'bt' => null,
                    'st' => null,
                    'ft' => null,
                    'xt_ft' => null,
                    'xt_ft2' => null,
                    'error' => null,
                );
            }

            $result['hasilRamal'] = $hasilRamal;
            $result['MAD'] = null;
            $result['MSE'] = null;
            $result['MAPE'] = null;
            $result['ratarataKesalahan'] = null;

            return $result;
        }

        // Fungsi metode triple exponential smoothing
        $h = new ExponentialSmoothing($alpha, $beta, $gamma, $L, $dataAktual);
        $dataForecast = $h->get_forecast();

        // Perhitungan error
        // rumus PE : ABS(xt-ft/xt)x100
        $arrPE = array();
        $arrPE2 = array();
        $PE = array();
        $MAD = 0;
        $MSE = 0;
        $MAPE = 0;
        for ($i = 0; $i < count($dataForecast); $i++) {
            if (isset($dataForecast[$i])) {
                // | xt-ft |
                $xtFt = $dataAktual[$i] - $dataForecast[$i];
                $arrPE[] = ABS($xtFt);
                // (xt-ft)^2
                $xtFt2 = pow($xtFt, 2);
                $arrPE2[] = $xtFt2;
                // ABS(xt-ft/xt)x100
                $APE = ABS($xtFt / $dataAktual[$i]) * 100;
                $PE[] = $APE;
                // Total
                $MAD += ABS($xtFt);
                $MSE += $xtFt2;
                $MAPE += $APE;
            } else {
                $arrPE[] = null;
                $arrPE2[] = null;
                $PE[] = null;
            }
        };

        $jmlAktual = count($dataForecast) - $L;
        $hasilMAD = $MAD / $jmlAktual;
        $hasilMSE = $MSE / $jmlAktual;
        $hasilMAPE = $MAPE / $jmlAktual;
        $hasilKeseluruhan = $hasilMAD + $hasilMSE + $hasilMAPE;
		    $ratarataKesalahan = $hasilKeseluruhan / 3;

        // proses merge data ramal aktual dengan bulan selanjutnya
        for ($i = count($dataAktual); $i < count($srs); $i++) {
            $dataForecast[] = $h->forecast($i);
        }

        // Peramalan
        $levels = $h->get_levels();
        $trens = $h->get_trens();
        $seasonals = $h->get_seasonals();
        for ($i = 0; $i < count($srs); $i++) {
            $hasilRamal[] =  array(
                'bulan' => $srs[$i]['bulan'],
                'jumlah' => $srs[$i]['jumlah'],
                'lt' => (isset($levels[$i])) ? round($levels[$i], 5) : null,
                'bt' => (isset($trens[$i])) ? round($trens[$i], 5) : null,
                'st' => (isset($seasonals[$i])) ? round($seasonals[$i], 5) : null,
                'ft' => (isset($dataForecast[$i])) ? round($dataForecast[$i], 5) : null,
                'xt_ft' => (isset($arrPE[$i])) ? round($arrPE[$i], 5) : null,
                'xt_ft2' => (isset($arrPE2[$i])) ? round($arrPE2[$i], 5) : null,
                'error' => (isset($PE[$i])) ? round($PE[$i], 5) : null,
            );
        }

        $result['hasilRamal'] = $hasilRamal;
        $result['MAD'] = round($hasilMAD, 4);
        $result['MSE'] = round($hasilMSE, 4);
        $result['MAPE'] = round($hasilMAPE, 4);
        $result['ratarataKesalahan'] = round($ratarataKesalahan, 4);

        return $result;
    }

    // Fungsi untuk testing perhitungan development
    public function forecast()
    {

        $starter = 0;
        $lb = 0;

        $dataAktual = [];
        $blnAwal = '2023-04-01';
        $blnAkhir = '2024-03-01';
        $blnRamal = '2024-05-01';

        $srs = array(
            array(
                'bulan' => '04-2023',
                'jumlah' => 32
            ),
            array(
                'bulan' => '05-2023',
                'jumlah' => 32
            ),
            array(
                'bulan' => '06-2023',
                'jumlah' => 33
            ),
            array(
                'bulan' => '07-2023',
                'jumlah' => 35
            ),
            array(
                'bulan' => '08-2023',
                'jumlah' => 38
            ),
            array(
                'bulan' => '09-2023',
                'jumlah' => 36
            ),
            array(
                'bulan' => '10-2023',
                'jumlah' => 36
            ),
            array(
                'bulan' => '11-2023',
                'jumlah' => 32
            ),
            array(
                'bulan' => '12-2023',
                'jumlah' => 33
            ),
            array(
                'bulan' => '01-2024',
                'jumlah' => 31
            ),
            array(
                'bulan' => '02-2024',
                'jumlah' => 33
            ),
            array(
                'bulan' => '03-2024',
                'jumlah' => 34
            ),
        );

        // Mengambil nilai data aktual
        foreach ($srs as $row) {
            $dataAktual[] = $row['jumlah'];
        }

        // generate list bulan dan jumlah data aktual, dari awal hingga akhir bulan kunjungan pada setiap pelayanan
        for ($t = date("Y", strtotime($blnAkhir)); $t <= date("Y", strtotime($blnRamal)); $t++) {
            if ($starter == 0) {
                $lb = date("m", strtotime($blnAkhir)) + 1;
            } else {
                $lb = 1;
            }

            for ($b = $lb; $b <= 13; $b++) {
                if ($b > 12) {
                    $starter = 1;
                    break;
                } else {

                    if ($t == date("Y", strtotime($blnRamal)) && $b > date("m", strtotime($blnRamal))) {
                        break;
                    } else {
                        // proses menambahkan / menggabungkan data series bulanan dengan bulan selanjutnya
                        $bulanStr = sprintf("%02d", $b) . "-" . $t;
                        $srs[] = array(
                            'bulan' => $bulanStr,
                            'jumlah' => null
                        );
                    }
                }
            }
        }

        $alpha = 0.5;
        $beta = 0.5;
        $gamma = 0.5;
        $L = 4;

        // $series = array(
        //     32,
        //     32,
        //     33,
        //     35,
        //     38,
        //     36,
        //     36,
        //     32,
        //     33,
        //     31,
        //     33,
        //     34
        // );

        // Fungsi metode triple exponential smoothing
        $h = new ExponentialSmoothing($alpha, $beta, $gamma, $L, $dataAktual);
        $dataForecast = $h->get_forecast();

        echo '<pre>';
        // print_r($srs);
        print_r($dataAktual);
        // print_r($h);
        echo '<br> Result forecast ori : <br>';
        print_r($dataForecast);
        echo '<br> Result forecast future : <br>';

        // Perhitungan error
        // rumus PE : ABS(xt-ft/xt)x100

        $arrPE = array();
        $arrPE2 = array();
        $PE = array();
        $MAD = 0;
        $MSE = 0;
        $MAPE = 0;
        for ($i = 0; $i < count($dataForecast); $i++) {
            if (isset($dataForecast[$i])) {
                // | xt-ft |
                $xtFt = $dataAktual[$i] - $dataForecast[$i];
                $arrPE[] = ABS($xtFt);
                // (xt-ft)^2
                $xtFt2 = pow($xtFt, 2);
                $arrPE2[] = $xtFt2;
                // ABS(xt-ft/xt)x100
                $APE = ABS($xtFt / $dataAktual[$i]) * 100;
                $PE[] = $APE;
                // Total
                $MAD += ABS($xtFt);
                $MSE += $xtFt2;
                $MAPE += $APE;
            } else {
                $arrPE[] = null;
                $arrPE2[] = null;
                $PE[] = null;
            }
        };

        $jmlAktual = count($dataForecast) - $L;
        echo '<br> xt-ft : <br>';
        print_r($arrPE);
        print_r($arrPE2);
        print_r($PE);
        echo '<br>SUM MAD :';
        print_r($MAD);
        echo '<br>SUM MSE :';
        print_r($MSE);
        echo '<br>SUM PE :';
        print_r($MAPE);
        echo '<br>JML DATA AKTUAL :';
        print_r($jmlAktual);

        $hasilMAD = $MAD / $jmlAktual;
        $hasilMSE = $MSE / $jmlAktual;
        $hasilMAPE = $MAPE / $jmlAktual;

        echo '<br>MAD :';
        print_r($hasilMAD);
        echo '<br>MSE :';
        print_r($hasilMSE);
        echo '<br>MAPE :';
        print_r($hasilMAPE);
        echo '<br>';

        // proses merge data ramal aktual dengan bulan selanjutnya
        for ($i = count($dataAktual); $i < count($srs); $i++) {
            echo '[' . $i . '] ' . $h->forecast($i);
            echo '<br>';
            $dataForecast[] = $h->forecast($i);
        }
        print_r($dataForecast);

        // Peramalan
        $hasilRamal = array();
        $levels = $h->get_levels();
        $trens = $h->get_trens();
        $seasonals = $h->get_seasonals();
        for ($i = 0; $i < count($srs); $i++) {
            $hasilRamal[] =  array(
                'bulan' => $srs[$i]['bulan'],
                'jumlah' => $srs[$i]['jumlah'],
                'lt' => (isset($levels[$i])) ? $levels[$i] : null,
                'bt' => (isset($trens[$i])) ? $trens[$i] : null,
                'st' => (isset($seasonals[$i])) ? $seasonals[$i] : null,
                'ft' => $dataForecast[$i],
                'xt_ft' => (isset($arrPE[$i])) ? $arrPE[$i] : null,
                'xt_ft2' => (isset($arrPE2[$i])) ? $arrPE2[$i] : null,
                'error' => (isset($PE[$i])) ? $PE[$i] : null,
            );
        }

        print_r($hasilRamal);
        echo '</pre>';

        return $hasilRamal;
    }
}
