<?php
/**
 * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
 *
 * @author Double Bastion LLC
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU Affero General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

declare(strict_types=1);

namespace OCA\PaxFax\Controller;

use OCP\IRequest;
use OCP\AppFramework\Controller;
use OCA\PaxFax\Service\PaxfaxService;
use OCP\AppFramework\App;
use OCP\Files\NotPermittedException;
use OCP\Files\Folder;
use OCP\IConfig;
use OC\Files\Filesystem;
use OC\Files\View;
use OCP\IUserSession;
use OC\URLGenerator;
use \ReflectionClass;
use \FilesystemIterator;

use Phaxio;
use Phaxio\OperationResult;
use Phaxio\Error\AuthenticationException;
use Phaxio\Error\NotFoundException;
use Phaxio\Error\InvalidRequestException;
use Phaxio\Error\RateLimitException;
use Phaxio\Error\APIConnectionException;
use Phaxio\Error\GeneralException;


class PaxfaxController extends Controller {

    private $service;
    private $config;
    private $userId;
    private $folder;
    private $filesystem;
    private $view;
    private $userSession;
    private $urlGenerator;

    public function __construct($appName, IRequest $request, PaxfaxService $service, IConfig $config, $userId, Folder $folder, Filesystem $filesystem, View $view, IUserSession $userSession, URLGenerator $urlGenerator) {

           parent::__construct($appName, $request);

           $this->service = $service;
           $this->config = $config;
           $this->userId = $userId;
           $this->folder = $folder;
           $this->filesystem = $filesystem;
           $this->view = $view;
           $this->userSession = $userSession;
           $this->urlGenerator = $urlGenerator;
    }


    /**
     * @NoAdminRequired
     */
    public function cleantempdir() {

           // If the 'temp_files' folder doesn't exist create it
           if ($this->folder->nodeExists('Pax_Fax/temp_files') == false) {
               $this->folder->newFolder('Pax_Fax/temp_files');
           }

           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
           $targetdir = $datadir . $this->userSession->getUser()->getUID() . "/files/Pax_Fax/temp_files";
           $fileSystemIterator = new FilesystemIterator($targetdir);

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo){
                    $dirfiles[] = $fileInfo->getFilename();
           }

           foreach ($dirfiles as $key => $indfile) {
                    $thisuserroot = $this->view->getRoot();
                    $tempfile = $thisuserroot . "/Pax_Fax/temp_files/" . $indfile;
                    $removetmpfile = $this->filesystem->unlink($tempfile);
           }
    }


    /**
     * @NoAdminRequired
     */
    public function object_to_array($obj) {

           if(is_object($obj)) $obj = (array)$this->dismount($obj);
           if(is_array($obj)) {
              $new = array();
              foreach($obj as $key => $val) {
                      $new[$key] = $this->object_to_array($val);
              }
           }
           else $new = $obj;
           return $new;
    }


    /**
     * @NoAdminRequired
     */
    public function dismount($object) {
           $reflectionClass = new ReflectionClass(get_class($object));
           $array = array();
           foreach ($reflectionClass->getProperties() as $property) {
                    $property->setAccessible(true);
                    $array[$property->getName()] = $property->getValue($object);
                    $property->setAccessible(false);
           }
           return $array;
    }


    /**
     * @NoAdminRequired
     */
    public function getbalance() {

           $apiMode = 'live';
           $thisapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID());

           $apiKeys[$apiMode] = $thisapicred[0];
           $apiSecrets[$apiMode] = $thisapicred[1];

           $apiHost = 'https://api.phaxio.com/v2.1/';

           $phaxio = new Phaxio($apiKeys[$apiMode], $apiSecrets[$apiMode], $apiHost);

           try {
                    // Get Phaxio account balance
                    $phaxioresulttert = $phaxio->doRequest("GET", 'account/status');

                    $balancetoarr = $this->object_to_array($phaxioresulttert);

                    $phaxiobalance = $balancetoarr['data']['balance'];

           } catch (InvalidRequestException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'invalid request error';
           } catch (AuthenticationException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'authentication error';
           } catch (APIConnectionException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'API connection error';
           } catch (RateLimitException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'rate limit error';
           } catch (NotFoundException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'not found error';
           } catch (GeneralException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'undefined error';
           }

           return $phaxiobalance;
    }


    /**
     * @NoAdminRequired
     */
    public function getfaxnumbers() {

           $apiMode = 'live';
           $thisapicred = $this->service->getapicredentials($this->userSession->getUser()->getUID());

           $apiKeys[$apiMode] = $thisapicred[0];
           $apiSecrets[$apiMode] = $thisapicred[1];

           $apiHost = 'https://api.phaxio.com/v2.1/';

           $phaxio = new Phaxio($apiKeys[$apiMode], $apiSecrets[$apiMode], $apiHost);

           try {
                    // Get all Phaxio fax numbers
                    $phaxioresultfour = $phaxio->doRequest("GET", 'phone_numbers');

                    $phaxionbstoarr = $this->object_to_array($phaxioresultfour);

                    $phaxioarr = [];

                    foreach ($phaxionbstoarr['data'] as $phkey => $phvalue) {
                           if (is_array($phvalue)) {
                                 foreach ($phvalue as $phkey2 => $phvalue2) {
                                       if ($phkey2 == 'phone_number') {
                                           $phaxioarr[] = $phvalue2;
                                       }
                                 }
                           }
                    }

                    $phaxionmbrs = $phaxioarr;

           } catch (InvalidRequestException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'invalid request error';
           } catch (AuthenticationException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'authentication error';
           } catch (APIConnectionException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'API connection error';
           } catch (RateLimitException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'rate limit error';
           } catch (NotFoundException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'not found error';
           } catch (GeneralException $e) {
                    $phaxiobalance = 'unknown';
                    $phaxiosuccess = 'false';
                    $errortype = 'undefined error';
           }

           return $phaxionmbrs;
    }

    /**
     * @NoAdminRequired
     */
    protected function getFileID() {
		if ($this->createdFile) {
			return $this->createdFile;
		}

		$qb = $this->connection->getQueryBuilder();

		// We create a new file entry and delete it after the test again
		$fileName = $this->getUniqueID('TestRepairCleanTags', 12);
		$qb->insert('filecache')
			->values([
				'path' => $qb->createNamedParameter($fileName),
				'path_hash' => $qb->createNamedParameter(md5($fileName)),
			])
			->execute();
		$fileName = $this->getUniqueID('TestRepairCleanTags', 12);
		$qb->insert('filecache')
			->values([
				'path' => $qb->createNamedParameter($fileName),
				'path_hash' => $qb->createNamedParameter(md5($fileName)),
			])
			->execute();

		$this->createdFile = (int) $this->getLastInsertID('filecache', 'fileid');
		return $this->createdFile;
    }

    /**
     * @NoAdminRequired
     */
    public function uploadfile($uploadfileforfax) {

           $fileContent = file_get_contents($_FILES['uploadfileforfax']['tmp_name']);
           $fileName = $_FILES['uploadfileforfax']['name'];
           $fileSizeinit = $_FILES['uploadfileforfax']['size'];
           $fileSize = $fileSizeinit / 1048576;

           if ($this->folder->nodeExists('Pax_Fax/faxes_sent') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_sent');
           }
           if ($this->folder->nodeExists('Pax_Fax/faxes_received') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_received');
           }
           if ($this->folder->nodeExists('Pax_Fax/faxes_sent_failed') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_sent_failed');
           }
           if ($this->folder->nodeExists('Pax_Fax/faxes_received_failed') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_received_failed');
           }
           if ($this->folder->nodeExists('Pax_Fax/temp_files') == false) {
               $this->folder->newFolder('Pax_Fax/temp_files');
           }

           $userroot = $this->view->getRoot();
           $targetfile = $userroot . "/Pax_Fax/temp_files/" . $fileName;

           $target = $this->folder->newFile($targetfile);
           $target->putContent($fileContent);

           // Get the cumulative files size of the uploaded files
           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
           $targetdir = $datadir . $this->userSession->getUser()->getUID() . "/files/Pax_Fax/temp_files";

           $fileSystemIterator = new FilesystemIterator($targetdir);

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo){
                    $dirfiles[] = $fileInfo->getFilename();
           }

           $totalflsizeinit = 0;
           foreach ($dirfiles as $key => $indfile) {
                    $fileSizeinit = $this->filesystem->filesize($userroot . "/Pax_Fax/temp_files/" . $indfile);
                    $mbSize = $fileSizeinit / 1048576;
                    $totalflsizeinit += $mbSize;
           }

           $totalflsize = number_format($totalflsizeinit, 2) . ' MB';

           return $totalflsize;
    }

    /**
     * @NoAdminRequired
     */
    public function pickfile($path) {

           if ($this->folder->nodeExists('Pax_Fax/faxes_sent') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_sent');
           }
           if ($this->folder->nodeExists('Pax_Fax/faxes_received') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_received');
           }
           if ($this->folder->nodeExists('Pax_Fax/faxes_sent_failed') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_sent_failed');
           }
           if ($this->folder->nodeExists('Pax_Fax/faxes_received_failed') == false) {
               $this->folder->newFolder('Pax_Fax/faxes_received_failed');
           }
           if ($this->folder->nodeExists('Pax_Fax/temp_files') == false) {
               $this->folder->newFolder('Pax_Fax/temp_files');
           }

           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';

           $fltgt = $datadir . $this->userSession->getUser()->getUID() . "/files" . $path;

           $fileContentpk = file_get_contents($fltgt);

           $patharr = explode("/", $path);

           $revarr = array_reverse($patharr);

           $relflpath = "/Pax_Fax/temp_files/" . $revarr[0]; 

           $target = $this->folder->newFile($relflpath);

           $target->putContent($fileContentpk);

           $targetdir = $datadir . $this->userSession->getUser()->getUID() . "/files/Pax_Fax/temp_files";

           $fileSystemIterator = new FilesystemIterator($targetdir);

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo) {
                    $dirfiles[] = $fileInfo->getFilename();
           }

           $totalflsizeinit = 0;

           foreach ($dirfiles as $key => $indfile) {

                    $fileSizeinit = $this->filesystem->filesize("/Pax_Fax/temp_files/" . $indfile);
                    $mbSize = $fileSizeinit / 1048576;
                    $totalflsizeinit += $mbSize;
           }

           $totalflsize = number_format($totalflsizeinit, 2) . ' MB';

           return $totalflsize;
    }

    /**
     * @NoAdminRequired
     */
    public function removeupfile($removedfilename) {

           $tmpfl = "/" . $this->userSession->getUser()->getUID() . "/files/Pax_Fax/temp_files/" . $removedfilename;

           $removefile = $this->view->unlink($tmpfl);

           // Get the cumulative files size of the uploaded files
           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
           $targetdir = $datadir . $this->userSession->getUser()->getUID() . "/files/Pax_Fax/temp_files";
           $fileSystemIterator = new FilesystemIterator($targetdir);

           $dirfiles = [];
           foreach ($fileSystemIterator as $fileInfo) {
                    $dirfiles[] = $fileInfo->getFilename();
           }

           $totalflsizeinit = 0;

           foreach ($dirfiles as $key => $indfile) {
                    $fileSizeinit = $this->filesystem->filesize("/Pax_Fax/temp_files/" . $indfile);
                    $mbSize = $fileSizeinit / 1048576;
                    $totalflsizeinit += $mbSize;
           }

           $totalflsize = number_format($totalflsizeinit, 2) . ' MB';

           return $totalflsize;
    }

    /**
     * @NoAdminRequired
     */
    public function getpickedfile($pickedfilename) {

           $thisuserroot = $this->view->getRoot();

           $temppickedfile = $thisuserroot . "/Pax_Fax/temp_files/" . $pickedfilename;
           $getfilecontent = $this->filesystem->file_get_contents($temppickedfile);

           $namesplit = explode(".", $pickedfilename);
           $extension = end($namesplit);

           if ($extension == "txt" || $extension == "html") {
               $getpickedfile = $getfilecontent;
           } elseif ($extension == "jpg") {
               $getpickedfile = 'data:image/jpeg;base64,' . base64_encode($getfilecontent);
           } elseif ($extension == "png") {
               $getpickedfile = 'data:image/png;base64,' . base64_encode($getfilecontent);
           } else { $getpickedfile = ""; }

           return $getpickedfile;
    }

    /**
     * @NoAdminRequired
     */
    public function sendfax($uploadedtofax, $selectedcid, $toNumber) {

           $tonumbertr = str_replace("+", "", $toNumber[0]);
           $fldate = date("Y-m-d_H-i-s_").gettimeofday()["usec"];

           $fromnumberdigits = str_replace("+", "", $selectedcid);
           if ($selectedcid != '' && $selectedcid != 'click refresh button') { $fromnumber = $fromnumberdigits; } else { $fromnumber = 'nocallerid'; }

           $countfaxfiles = count($uploadedtofax);

           $openedfiles = [];
           $crtuser = $this->userSession->getUser()->getUID();

           foreach ($uploadedtofax as $key => $flname) {

                    if ($key == 0) { $firstflname = $flname; }

                    $fileNamesec = array_reverse(explode(".", $flname));
                    $filenameext = $fileNamesec[0];
                    array_shift($fileNamesec);

                    $fileName = implode("", $fileNamesec);

                    if ($countfaxfiles == 1) {
                        $targetfile = "/Pax_Fax/faxes_sent/" . $fileName . "_" . $fromnumber . "_"  . $tonumbertr . "_" . $fldate . "." . $filenameext;
                    } else {
                         if ($this->folder->nodeExists("Pax_Fax/faxes_sent/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate) == false) {
                             $this->folder->newFolder("Pax_Fax/faxes_sent/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate);
                         }

                         $targetfile = "/Pax_Fax/faxes_sent/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "/" . $fileName . "_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext;
                    }

                    $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';

                    $fltgtsnd = $datadir . $crtuser . "/files/Pax_Fax/temp_files/" . $flname;
                    $fltgtsndtmp = "/Pax_Fax/temp_files/" . $flname;

                    $fileContentsnd = file_get_contents($fltgtsnd);

                    $target = $this->folder->newFile($targetfile);
                    $target->putContent($fileContentsnd);

                    $removetmpfile = $this->filesystem->unlink($fltgtsndtmp);

                    if ($countfaxfiles == 1) {
                        $openedfiles[] = fopen($datadir . $crtuser . "/files/Pax_Fax/faxes_sent/" . $fileName . "_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext, "r");
                    } else {
                        $openedfiles[] = fopen($datadir . $crtuser . "/files/Pax_Fax/faxes_sent/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "/" . $fileName . "_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext, "r");
                    }
           }

           $params = array(
                           'to' => $toNumber,
                           'file' => $openedfiles,
                           'caller_id' => $selectedcid
                     );

           $apiMode = 'live';

           $thisapicred = $this->service->getapicredentials($crtuser);

           $apiKeys[$apiMode] = $thisapicred[0];
           $apiSecrets[$apiMode] = $thisapicred[1];

           $apiHost = 'https://api.phaxio.com/v2.1/';

           $phaxio = new Phaxio($apiKeys[$apiMode], $apiSecrets[$apiMode], $apiHost);

           try {
                    $phaxioresultinit = $phaxio->sendFax($params);

                    $phaxioresultsec = $phaxio->doRequest("GET", 'faxes/' . urlencode((string)$phaxioresultinit['id']));

                    $statustoarr = $this->object_to_array($phaxioresultsec);

                    $phaxiosuccess = $statustoarr['success'];

                    $errortype = 'there are no errors';

           } catch (InvalidRequestException $e) {
                    $phaxiosuccess = 'false';
                    $errortype = 'invalid request error';
           } catch (AuthenticationException $e) {
                    $phaxiosuccess = 'false';
                    $errortype = 'authentication error';
           } catch (APIConnectionException $e) {
                    $phaxiosuccess = 'false';
                    $errortype = 'API connection error';
           } catch (RateLimitException $e) {
                    $phaxiosuccess = 'false';
                    $errortype = 'rate limit error';
           } catch (NotFoundException $e) {
                    $phaxiosuccess = 'false';
                    $errortype = 'not found error';
           } catch (GeneralException $e) {
                    $phaxiosuccess = 'false';
                    $errortype = 'undefined error';
           }

           $phaxioresult = ['success' => $phaxiosuccess, 'errortype' => $errortype];

           if ($phaxiosuccess != 'true') {

                    foreach ($uploadedtofax as $key => $flname) {

                        $fileNamesec = array_reverse(explode(".", $flname));
                        $filenameext = $fileNamesec[0];
                        array_shift($fileNamesec);

                        $fileName = implode("", $fileNamesec);

                        if ($countfaxfiles == 1) {
                            $failedfl = "/Pax_Fax/faxes_sent/" . $fileName . "_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext;
                            $newtargetfl =  "/Pax_Fax/faxes_sent_failed/" . $fileName . "_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext;
                        } else {

                            $failedfl = "/Pax_Fax/faxes_sent/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "/" . $fileName . "_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext;
                            $this->folder->newFolder("Pax_Fax/faxes_sent_failed/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate);
                            $newtargetfl = "/Pax_Fax/faxes_sent_failed/" . $firstflname . "_et_al_" . $fromnumber . "_" . $tonumbertr . "_" . $fldate . "/" . $fileName . "_" . $tonumbertr . "_" . $fldate . "." . $filenameext;
                        }

                        $fileContentfld = $this->filesystem->file_get_contents($failedfl);

                        $targetact = $this->folder->newFile($newtargetfl);
                        $targetact->putContent($fileContentfld);

                        $removefailed = $this->filesystem->unlink($failedfl);
                    }

           }

           return $phaxioresult;
    }


    /**
     * @NoAdminRequired
     */
    public function getsettings() {
           return $this->service->getsettings($this->userSession->getUser()->getUID());
    }


    /**
     * @NoAdminRequired
     */
    public function updatesettings($apiKey, $apiSecret, $webhookToken, $receiveUrl, $getNotification, $notificationEmail) {
           return $this->service->updatesettings($this->userSession->getUser()->getUID(), $apiKey, $apiSecret, $webhookToken, $receiveUrl, $getNotification, $notificationEmail);
    }

}
