<?php
/*******************************************************************************

    Copyright 2014 Whole Foods Co-op

    This file is part of IT CORE.

    IT CORE is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    IT CORE 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    in the file license.txt along with IT CORE; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*********************************************************************************/

use League\Flysystem\Sftp\SftpAdapter;
use League\Flysystem\Filesystem;

include(dirname(__FILE__).'/../../../config.php');
if (!class_exists('FannieAPI')) {
    include(__DIR__ . '/../../../classlib2.0/FannieAPI.php');
}

/**
*/
class SpinsSubmitTask extends FannieTask 
{
    public $name = 'Submit SPINS data';

    public $description = 'Submits weekly sales data to SPINS. SPINS plugin must be configured
    with proper FTP credentials';

    public $default_schedule = array(
        'min' => 0,
        'hour' => 4,
        'day' => '*',
        'month' => '*',
        'weekday' => '2',
    );

    public function run()
    {
        global $argv, $FANNIE_OP_DB, $FANNIE_PLUGIN_SETTINGS;
        $dbc = FannieDB::get($FANNIE_OP_DB);
        $dateObj = new SpinsDate($FANNIE_PLUGIN_SETTINGS['SpinsOffset']);

        $upload = true;

        /**
          Handle additional args
        */
        if (isset($argv) && is_array($argv)) {
            foreach($argv as $arg) {
                if (is_numeric($arg)) {
                    $dateObj = new SpinsDate($FANNIE_PLUGIN_SETTINGS['SpinsOffset'], $arg);
                } elseif ($arg == '--file') {
                    $upload = false;
                }
            }
        }

        $spins_week = $dateObj->spinsWeek();
        $dlog = DTransactionsModel::selectDlog($dateObj->startDate(), $dateObj->endDate());
        $lastDay = date("M d, Y", $dateObj->endTimeStamp()) . ' 11:59PM'; 

        $this->cronMsg('SPINS data for week #' . $spins_week . '(' . $dateObj->startDate() . ' to ' . $dateObj->endDate() . ')', FannieLogger::INFO);

        $filename = $FANNIE_PLUGIN_SETTINGS['SpinsPrefix'];
        if ($this->config->get('STORE_MODE') == 'HQ') {
            $filename .= sprintf('%02d', $this->config->get('STORE_ID'));
        }
        if (!empty($filename)) {
            $filename .= '_';
        }
        $filename .= date('mdY', $dateObj->endTimeStamp()) . '.csv';

        // Odd "CASE" statement is to deal with special order
        // line items the have case size & number of cases
        $dataQ = "SELECT d.upc, p.description,
                    SUM(CASE WHEN d.quantity <> d.ItemQtty AND d.ItemQtty <> 0 THEN d.quantity*d.ItemQtty ELSE d.quantity END) as quantity,
                    SUM(d.total) AS dollars,
                    '$lastDay' AS lastDay
                  FROM $dlog AS d
                    " . DTrans::joinProducts('d', 'p', 'INNER') . "
                  WHERE p.Scale = 0
                    AND d.upc > '0000000999999' 
                    AND tdate BETWEEN ? AND ?
                    " . ($this->config->get('STORE_MODE') == 'HQ' ? ' AND d.store_id=? ' : '') . "
                  GROUP BY d.upc, p.description";

        $outfile = sys_get_temp_dir()."/".$filename;
        $fp = fopen($outfile,"w");

        $dataP = $dbc->prepare($dataQ);
        $args = array($dateObj->startDate() . ' 00:00:00', $dateObj->endDate() . ' 23:59:59');
        if ($this->config->get('STORE_MODE') == 'HQ') {
            $args[] = $this->config->get('STORE_ID');
        }
        $dataR = $dbc->execute($dataP, $args);
        while($row = $dbc->fetch_row($dataR)){
            for($i=0;$i<4; $i++){
                if ($i==2 || $i==3) {
                    $row[$i] = sprintf('%.2f', $row[$i]);
                }
                fwrite($fp,"\"".$row[$i]."\",");
            }
            fwrite($fp,"\"".$row[4]."\"\n");
        }
        fclose($fp);

        if ($upload) {
            $server = isset($FANNIE_PLUGIN_SETTINGS['SpinsFtpServer']) ? $FANNIE_PLUGIN_SETTINGS['SpinsFtpServer'] : 'ftp.spins.com';
            $this->cronMsg("will attempt FTP upload to: $server", FannieLogger::INFO);

            $attempts = 0;
            $maxAttempts = isset($FANNIE_PLUGIN_SETTINGS['SpinsUploadAttempts']) ? $FANNIE_PLUGIN_SETTINGS['SpinsUploadAttempts'] : 1;
            $delay = isset($FANNIE_PLUGIN_SETTINGS['SpinsRetryDelay']) ? $FANNIE_PLUGIN_SETTINGS['SpinsRetryDelay'] : 30;
            while (true) {
                if ($FANNIE_PLUGIN_SETTINGS['SpinsSftp'] && $this->sftp_upload($server, $outfile, $filename)) {
                    $this->cronMsg('SFTP upload successful', FannieLogger::INFO);
                    break;
                } elseif (!$FANNIE_PLUGIN_SETTTINGS['SpinsSftp'] && $this->upload($server, $outfile, $filename)) {
                    $this->cronMsg('FTP upload successful', FannieLogger::INFO);
                    break;
                }
                $attempts++;
                $this->cronMsg("FTP upload attempt #$attempts of $maxAttempts failed", FannieLogger::WARNING);
                if ($attempts >= $maxAttempts) {
                    $this->cronMsg("Reached max of $maxAttempts attempts; giving up on FTP upoad", FannieLogger::ERROR);
                    break;
                }
                sleep($delay);
            }

            unlink($outfile);

        } else {
            rename($outfile, './' . $filename);    
            $this->cronMsg('Generated file: ' . $filename, FannieLogger::INFO);
        }
    }

    public function upload($server, $localPath, $filename) {
        global $FANNIE_PLUGIN_SETTINGS;

        $conn_id = ftp_connect($server);
        $login_id = ftp_login($conn_id, $FANNIE_PLUGIN_SETTINGS['SpinsFtpUser'], $FANNIE_PLUGIN_SETTINGS['SpinsFtpPw']);
        if (!$conn_id || !$login_id) {
            $this->cronMsg('FTP Connection failed', FannieLogger::ERROR);
            return false;
        }

        $remoteDir = isset($FANNIE_PLUGIN_SETTINGS['SpinsFtpDir']) ? $FANNIE_PLUGIN_SETTINGS['SpinsFtpDir'] : 'data';
        if ($remoteDir) {
            ftp_chdir($conn_id, $remoteDir);
        }
        ftp_pasv($conn_id, true);
        $uploaded = ftp_put($conn_id, $filename, $localPath, FTP_ASCII);
        ftp_close($conn_id);
        return $uploaded;
    }

    public function sftp_upload($server, $localPath, $filename)
    {
        $settings = FannieConfig::config('PLUGIN_SETTINGS');
        $adapter = new SftpAdapter(array(
            'host' => $server,
            'username' => $settings['SpinsFtpUser'],
            'password' => $settings['SpinsFtpPw'],
            'port' => 22,
        ));

        $filesystem = new Filesystem($adapter);
        $success = $filesystem->put($settings['SpinsFtpUser'] . '/' . $filename, file_get_contents($localPath));

        return $success;
    }
}
