<?php

//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
//\\\       \\\\\\\\|
//\\\ @@    @@\\\\\\| Hierophant Product Listener Plugin
//\\ @@@@  @@@@\\\\\|
//\\\@@@@| @@@@\\\\\|
//\\\ @@ |\\@@\\\\\\| http://www.smilingsouls.net/hierophant
//\\\\  ||   \\\\\\\| (c) Copyright 2008 Richard York, All rights Reserved
//\\\\  \\_   \\\\\\|
//\\\\\        \\\\\| Use and redistribution are subject to the terms of the license.
//\\\\\  ----  \@@@@| http://www.smilingsouls.net/hierophant/license
//@@@@@\       \@@@@|
//@@@@@@\     \@@@@@|
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
/**
* This is a collection of AJAX-callable methods for product management.

* Each method can be called via a special URL... 
* http://www.example.com/plugins/hProduct/query? <arguments>  
*
* The preceding URL calls the hProductListener plugin.

* The method name appears in the URL. Security is provided by 
* registering each method that is publically accessible in a 
* database, this prevents a user from calling *any* method 
* in the plugin, which would be a potential security risk.
*/ 

class hProductListener extends hListenerApplication {

    private 
$hProduct;
    private 
$hSpotlightSearch;
    private 
$hFileIcon;
    
    public function 
hConstructor()
    {
        
// Get the Product Library API Plugin
        
$this->hProduct $this->hFramework->hLibrary('hProduct');
    }

    public function 
isEmployee()
    {
        
// Is the current user logged in?
        // If not, return status code -6
        
if (!$this->hFramework->isLoggedIn())
        {
            
$this->XML(-6);
            return 
false;
        }

        
// Is the current user an Employee? 
        // If not, return status code -1
        
if (!$this->hFramework->inGroup('Employees'))
        {
            
$this->XML(-1);
            return 
false;
        }

        return 
true;
    }

    
/**
     * The following method queries the product database, using the database columns 
     * allowed in hProductLibrary::setSpotlightSearchColumns().
     *
     */
    
public function query()
    {
        
$this->hProduct->setSpotlightSearchColumns();
        
        
$this->hSpotlightSearch $this->hLibrary('hFramework/hSpotlight/hSpotlightSearch');

        
$results = array();
        
        
$where null;
        
$time null;

        
// Queries the database for the search terms.
        // See the hSpotlightSearch API for more information.
        
$this->hSpotlightSearch->query(''$_POST['hSpotlightSearchQuery'], $where$time'`hProducts`.`hProductName`''ASC'null$results'%.%');

        
$html '';

        
// Format the results.
        
foreach ($results as $key => $data)
        {
            
$html .=
                
"<div class='hProductRecord".($i 1' hProductRecordOdd' '')."' id='hProductRecordID-{$data['hProductID']}'>".
                    
"<span class='hProductID'>{$data['hProductID']}</span>".
                    
"<ul>".
                        
"<li class='hProductName'>{$data['hProductName']}</li>".
                        
"<li class='hProductPartNumber'>{$data['hProductPartNumber']}</li>".
                    
"</ul>".
                
"</div>";

            
$i++;
        }

        
// Send the client an HTML fragment, which can be inserted into a document 
        // using JavaScript without reloading the document.
        
$this->HTML($html);
    }

    
/**
     * Returns an XML docuemnt containing all data relevant to a particular product.
     * 
     *
     */
    
public function getProductData()
    {
        
// Has the hProductID argument been passed? 
        // If not, return status code -5
        
if (!isset($_GET['hProductID']))
        {
            
$this->XML(-5);
            return;
        }

        
// Get the product data
        
$query db::query(
            
"SELECT `hProductID`,
                    `hProductPartNumber`,
                    `hProductFiles`,
                    `hProductMatch`,
                    `hProductName`,
                    `hProductDescription`
               FROM `hProducts`
              WHERE `hProductID` = "
. (int) $_GET['hProductID']
        );

        
$xml "\n";

        
$count db::numRows($query);

        
// If the product exists
        
if ($count)
        {
            if (
$count 1)
            {
                
// If too many products exist return an error.
                
$xml .= "  <hProductError>1</hProductError>\n";
            }
        }
        else 
        {
            
// If the product does not exist return an error.
            
$xml .= "  <hProductError>0</hProductError>\n";
        }

        
$hFiles = array();

        
// Format the data in an XML document.
        
while ($data db::fetchArray($query))
        {
            foreach (
$data as $key => $value)
            {
                
$xml .= "  <{$key}>".hString::entitiesToUTF8($value)."</{$key}>\n";

                
                
// Take the product files, explode them into an array, 
                // and set them aside.
                
if ($key == 'hProductFiles')
                {
                    
$hFiles explode(','$value);
                    
sort($hFiles);
                }
            }
        }

        
// Get file data for each product file,
        // including the product's icon, title, path, and id.
        
if (is_array($hFiles))
        {
            
$this->hFileIcon $this->hLibrary('hFile/hFileIcon');

            
$xml .= "  <hFiles>\n";

            foreach (
$hFiles as $hFileID)
            {
                
$xml .=
                    
"    <hFile>\n".
                    
"      <hFileID>{$hFileID}</hFileID>\n".
                    
"      <hFileIcon>".$this->hFileIcon->getProductIcon($hFileID)."</hFileIcon>\n".
                    
"      <hFileTitle>".hString::entitiesToUTF8($this->hFramework->getFileTitle($hFileID))."</hFileTitle>\n".
                    
"      <hFilePath>".$this->hFramework->getFilePathByID($hFileID)."</hFilePath>\n".
                    
"    </hFile>\n";
            }

            
$xml .= "  </hFiles>\n";
        }

        
$this->XML($xml);
        return;
    }

    
/**
    * Return a part number for a product with options, 
    * or a product with replaced digits ("X" part numbers).
    * 
    * e.g., configurable products.  This API lets you return 
    * the correct configured part number on the fly, as a product 
    * is being configured on the client-side.
    */
    
public function getPartNumber()
    {
        
$xml 1;

        if (isset(
$_GET['hProductFiles']))
        {
            
$files explode(','$_GET['hProductFiles']);
            
sort($filesSORT_NUMERIC);
            
$xml $this->hProduct->getPartNumber(implode(','$files));
        }
        else
        {
            
$xml = -5;
        }

        
$this->XML($xml);
    }

    
/**
     * Get the price for a part number.  
     * 
     */    

    
public function getPrice()
    {
        if (!
$this->hProduct->canModifyPrice())
        {
             
$this->XML(-1);
             return;   
        }
        
        if (!isset(
$_GET['hProductPartNumber']))
        {
            
$this->XML(-5);
            return;
        }

        
$this->XML($this->hProduct->getPriceByPartNumber($_GET['hProductPartNumber']));
    }

    
/**
     * Get all pricing for a part number (for multiple pricing categories).
     * 
     *
     */
    
public function getPricing()
    {
        if (!isset(
$_GET['hProductID']) || !isset($_GET['hFileID']))
        {
            
$this->XML(-5);
            return;
        }
        
        if (!
$this->isEmployee())
        {
            return;
        }

        
$query $this->queryPricing(12$_GET['hProductID']);

        
$count db::numRows($query);

        
$xml "  <hProductPriceBy>".($count1)."</hProductPriceBy>";

        if (
$count)
        {
            
$this->getPricingXML($query$xml);
        }
        else
        {
            
$this->getPricingXML(
                
$this->queryPricing(1$_GET['hFileID']),
                
$xml
            
);
        }

        
$this->XML($xml);
        return;
    }
    
    
/**
     * Save a product's pricing.
     *
     */

    
public function savePricing()
    {
        if (!isset(
$_GET['hProductID']) || !isset($_GET['hFileID']))
        {
            
$this->XML(-5);
            return;
        }

        if (!
$this->isEmployee())
        {
            return;
        }

        
$hFrameworkResourceID  = (!empty($_POST['hProductPriceBy']))? 12;
        
$hFrameworkResourceKey = (!empty($_POST['hProductPriceBy']))? (int) $_GET['hFileID'] : (int) $_GET['hProductID'];

        
$hProductPriceIDs = array();

        
// Get current price ids... 
        
$query db::query(
            
"SELECT `hProductPriceID`
               FROM `hProductPrices`
              WHERE `hFrameworkResourceID` = 1
                AND `hFrameworkResourceKey` = "
. (int) $_GET['hFileID'] ."
                 OR `hFrameworkResourceID` = 12
                AND `hFrameworkResourceKey` = "
. (int) $_GET['hProductID']
        );

        while (
$data db::fetchArray($query))
        {
            
array_push($hProductPriceIDs$data['hProductPriceID']);
        }

        
// var_dump($hProductPriceIDs);
        
        
$submittedPriceIDs = array();
        
        if (isset(
$_POST['hProductPrice']) && is_array($_POST['hProductPrice']))
        {
            foreach (
$_POST['hProductPrice'] as $hProductPriceID => $hProductPrice)
            {
                if (
$hProductPriceID <= 0)
                {
                    
db::query(
                        
"INSERT INTO `hProductPrices` (
                            `hProductPriceID`,
                            `hProductPriceCategoryID`,
                            `hFrameworkResourceID`,
                            `hFrameworkResourceKey`,
                            `hProductPrice`
                        ) VALUES ( 
                            null,
                            "
. (int) $_POST['hProductPriceCategoryID'][$hProductPriceID] .",
                            "
. (int) $hFrameworkResourceID  .",
                            "
. (int) $hFrameworkResourceKey .",
                            "
. (float) $hProductPrice ."
                        )"
                    
);
                }
                else
                {
                    
db::query(
                        
"UPDATE `hProductPrices`
                            SET `hProductPriceCategoryID` = "
. (int) $_POST['hProductPriceCategoryID'][$hProductPriceID] .",
                                `hFrameworkResourceID`    = "
. (int) $hFrameworkResourceID .",
                                `hFrameworkResourceKey`   = "
. (int) $hFrameworkResourceKey",
                                `hProductPrice`           = "
. (float) $hProductPrice ."
                          WHERE `hProductPriceID`         = "
. (int) $hProductPriceID
                    
);

                    
array_push($submittedPriceIDs, (int) $hProductPriceID);
                }
            }
        }

        foreach (
$hProductPriceIDs as $hProductPriceID)
        {
            if (!
in_array($hProductPriceID$submittedPriceIDs))
            {
                
db::query(
                    
"DELETE
                       FROM `hProductPrices`
                      WHERE `hProductPriceID` = "
$hProductPriceID
                
);
            }
        }
    }
    
    private function 
queryPricing($hFrameworkResourceID$hFrameworkResourceKey)
    {
        return 
db::query(
            
"SELECT `hProductPriceID`,
                    `hProductPriceCategoryID`,
                    `hProductPrice`
               FROM `hProductPrices`
              WHERE `hFrameworkResourceID`  = "
. (int) $hFrameworkResourceID ."
                AND `hFrameworkResourceKey` = "
. (int) $hFrameworkResourceKey
        
);
    }

    private function 
getPricingXML($query, &$xml)
    {
        while (
$data db::fetchArray($query))
        {
            
$xml .= 
                
"  <hProductPrice ".
                    
"hProductPriceID=\"{$data['hProductPriceID']}\" ".
                    
"hProductPriceCategoryID=\"{$data['hProductPriceCategoryID']}\">".
                        
$data['hProductPrice'].
                
"</hProductPrice>\n";
        }
    }
    
    public function 
save()
    {
        if (!isset(
$_POST['hProductPartNumber']) || empty($_POST['hProductPartNumber']) || !isset($_POST['hProductID']))
        {
            
$this->XML(-5);
            return;
        }

        if (!
$this->isEmployee())
        {
            return;
        }

        if (!empty(
$_POST['hProductID']))
        {
            
db::query(
                
"UPDATE `hProducts`
                    SET `hProductPartNumber`  = '{$_POST['hProductPartNumber']}',
                        `hProductFiles`       = '{$_POST['hProductFiles']}',
                        `hProductMatch`       = "
. (int) $_POST['hProductMatch'] .",
                        `hProductName`        = '{$_POST['hProductName']}',
                        `hProductDescription` = '{$_POST['hProductDescription']}'
                  WHERE `hProductID`          = "
. (int) $_POST['hProductID']
            );

            
$this->XML((int) $_POST['hProductID']);
        }
        else
        {
            
db::query(
                
"INSERT INTO `hProducts` (
                    `hProductID`,
                    `hProductPartNumber`,
                    `hProductFiles`,
                    `hProductMatch`,
                    `hProductName`,
                    `hProductDescription`
                ) VALUES (
                    null,
                    '{$_POST['hProductPartNumber']}',
                    '{$_POST['hProductFiles']}',
                    "
. (int) $_POST['hProductMatch'] .",
                    '{$_POST['hProductName']}',
                    '{$_POST['hProductDescription']}'
                )"
            
);

            
$this->XML(db::insertID());
        }
    }
    
    public function 
import()
    {
        if (!
$this->isEmployee())
        {
            return;
        }
        
        if (empty(
$_FILES['hProductImportCSV']['tmp_name']) || empty($_POST['hProductImportBase']))
        {
            
$this->XML(-5);
            return;
        }

        
$file fopen($_FILES['hProductImportCSV']['tmp_name'], 'r');
        
$hFileID = (int) $_POST['hProductImportBase'];

        while (
false !== ($data fgetcsv($file10000',')))
        {
            
$files = array();

            
$continue false;

            foreach (
$_POST['hProductImportType'] as $i => $type)
            {
                
$c $i 1// CSV is offset from zero, not one.

                
$data[$c] = trim($data[$c]);

                
$setPrice false;

                switch (
$type)
                {
                    case 
'hProductPartNumber':
                    {
                        
$hProductPartNumber $data[$c];
                        break;
                    }
                    case 
'hProductFile':
                    {
                        if (!empty(
$data[$c]))
                        {
                            if (isset(
$_POST['hProductImportFile'][$i]))
                            {
                                
$files[] = (int) $_POST['hProductImportFile'][$i];
                            }
                            else
                            {
                                
// The column is not specified... skip it.
                                
$continue true;
                            }
                        }

                        break;
                    }
                    case 
'hProductName':
                    {
                        
$hProductName $data[$c];
                        break;
                    }
                    case 
'hProductDescription':
                    {
                        
$hProductDescription $data[$c];
                        break;
                    }
                    case 
'hProductPrice':
                    {
                        
$hProductPrice $data[$c];
                        
$setPrice true;
                        break;
                    }
                }
            }

            if (
$continue)
            {
                continue;
            }

            
$files[] = $hFileID;

            
sort($files);

            if (!empty(
$hProductPartNumber))
            {
                
$query db::query(
                    
"SELECT `hProductID`
                       FROM `hProducts`
                      WHERE `hProductPartNumber` = '{$hProductPartNumber}'"
                
);

                
$count db::numRows($query);

                if (!
$count && empty($hProductName) || $count && !empty($_POST['hProductImportExists']))
                {
                    
$hProductName $this->hFramework->getFileTitle($hFileID);
                }

                if (!
$count && empty($hProductDescription) || $count && !empty($_POST['hProductImportExists']))
                {
                    
$hProductDescription 
                        
trim(strip_tags($this->hFramework->getFileDocument($hFileID))).
                        
"\n\nConfigured With:\n\n";

                    foreach (
$files as $fileID)
                    {
                        if (
$fileID != $hFileID)
                        {
                            
$hProductDescription .= $this->hFramework->getFileTitle($fileID)."\n";
                        }
                    }
                }

                if (
$count)
                {
                    
$hProductID db::result($query);
                    
                    
db::query(
                        
"UPDATE `hProducts`
                            SET `hProductFiles`       = '"
.implode(','$files)."',
                                `hProductMatch`       = 0,
                                `hProductName`        = '{$hProductName}',
                                `hProductDescription` = '{$hProductDescription}'
                          WHERE `hProductID`          = "
$hProductID
                    
);
                }
                else
                {
                    
db::query(
                        
"INSERT INTO `hProducts` (
                            `hProductID`,
                            `hProductPartNumber`,
                            `hProductFiles`,
                            `hProductMatch`,
                            `hProductName`,
                            `hProductDescription`
                        ) VALUES (
                            null,
                            '{$hProductPartNumber}',
                            '"
.implode(','$files)."',
                            0,
                            '{$hProductName}',
                            '{$hProductDescription}'
                        )"
                    
);

                    
$hProductID db::insertID();
                }

                
db::query(
                    
"DELETE
                       FROM `hProductPrices`
                      WHERE `hFrameworkResourceID` = 12
                        AND `hFrameworkResourceKey` = {$hProductID}"
                
);

                if (!empty(
$hProductPrice) && !empty($_POST['hProductImportPriceCategory']))
                {
                    
db::query(
                        
"INSERT INTO `hProductPrices` (
                            `hProductPriceID`,
                            `hProductPriceCategoryID`,
                            `hFrameworkResourceID`,
                            `hFrameworkResourceKey`,
                            `hProductPrice`
                        ) VALUES (
                            null,
                            "
. (int) $_POST['hProductImportPriceCategory'] .",
                            12,
                            {$hProductID},
                            "
. (float) $hProductPrice ."
                        )"
                    
);
                }
            }
        }

        
$this->HTML(
            
"<html>\n".
            
"    <head></head>\n".
            
"    <body onload='top.hProduct.processImport(1);'>\n".
            
"    </body>\n".
            
"</html>\n"
        
);
    }
}

?>