<?php
/****************************************************************************
 *																			*
 * Copyright (c) 2005 ISPG Technologies (I) Pvt Ltd. All rights reserved.	*
 *																			*
 * This  is  commercial  software,  only  users  who have purchased a valid	*
 * license  and  accept  to the terms of the  License Agreement can install	*
 * and use this program.														*
 *																			*
 * ***************************************************************************
 * PLEASE READ THE FULL TEXT OF THE SOFTWARE LICENSE AGREEMENT IN THE		*
 * "copyright.txt" FILE PROVIDED WITH THIS DISTRIBUTION PACKAGE.				*
 * ***************************************************************************/
//
//$Id: EximModel.php, v 1.0 2013/09/09 20:52:11- created by Sreeja Venugopal
//
class EximModel extends Model {
    public $lang_xml;
    public $import_error;
    public $import_status = array();
    public $import_db_skip_new = 0;
    public $import_db_skip_exist = 0;
    public function getProductSchema($setID, $pre_process = '', $businessID = '', $brandID = '', $searchProductCategory = '',$lang_code='1') {
        //
        // Schema definition for Products
        //		
        
        $timeZone         = '';
        $default_currency = '';
        $status			  = '';
        if (!empty($pre_process)) {
            $timeZone         = $pre_process['productTimeZone'];
            $default_currency = $pre_process['productDefaultCurrency'];
            $status 		  = isset($pre_process['status']) ? $pre_process['status']  : "";
        }
        if (!empty($setID))
            $conditionArry = array(
                'attributeSetID' => $setID,
                'productStatus' => '!Deleted'
            );
        else
            $conditionArry = array(
                'productStatus' => '!Deleted'
            );
//        if (!empty($businessID))
//            $conditionArry['&products_options_business.businessID'] = $businessID;
        if (!empty($brandID))
            $conditionArry['&products.brandID'] = $brandID;
        if (!empty($searchProductCategory))
            $conditionArry['&products.productID'] = $searchProductCategory;
        
        if (!empty($businessID)){
            $sqlProdOptBusJoin      =   array(
                                            'productOptionID' => '~product_options.productOptionID',
                                            'businessID' => $businessID
                                        );
        }else{
            $sqlProdOptBusJoin      =   array(
                                            'productOptionID' => '~product_options.productOptionID',
                                            'businessOptionDefault' => 'Yes'
                                        );
        }
        $schema = array(
            'section' => 'products',
            'name' => 'products',
            'pattern_id' => 'products',
            'key' => array(
                'productID'
            ),
            'order' => 0,
            'table' => 'products',
            'alt_table' => 'product_options',
            'alt_table_key' => 'productID',
            'alt_condition' => array(
                'productOptionStatus' => '!Delete'
            ),
            'condition' => $conditionArry,
            'references' => array(
                'product_details' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'languageID' => $lang_code
                    ),
                    'join_type' => 'LEFT'
                ),
                'product_options' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'productOptionDefault' => 'Yes'
                    ),
                    'join_type' => 'LEFT'
                ),
                'products_options_business' => array(
                    'reference_fields' => $sqlProdOptBusJoin,
                    'join_type' => 'LEFT'
                )
            ),
            'post_processing' => array(
                'fn_exim_reset_extra',
                '$insert_ids',
                '1',
                $timeZone,
                $default_currency,
				$status
            ),
            'notes' => array(
                'text_exim_import_options_note',
                'text_exim_import_features_note',
                'text_exim_import_images_note',
                'text_exim_import_files_note' 
            ),
            'options' => array(
                'images_path' => array(
                    'title' => 'images_directory',
                    'description' => 'text_images_directory',
                    'type' => 'input',
                    'default_value' => 'DIR_IMAGES' . 'backup'
                ),
                'files_path' => array(
                    'title' => 'files_directory',
                    'description' => 'text_files_directory',
                    'type' => 'input',
                    'default_value' => 'DIR_DOWNLOADS' . 'backup'
                )
            ),
            'export_fields' => array(
                'Product ID' => array(
                    'process_get' => array(
                        'fn_exim_get_key',
                        '#key'
                    ),
                    'linked' => false
                ),
                'URL Key' => array(
                    'db_field' => 'productUrl',
                    'convert_put' => array(
                        'fn_clean_productUrl'
                    ),
                    'return_result' => true
                ),
                'Product SKU' => array(
                    'table' => 'product_options',
                    'db_field' => 'optionSKU',
                    'required' => true,
                    'alt_key' => true
                ),
                'Variant Title' => array(
                    'linked' => false, // this field is not linked during import-export					
                    'process_get' => array(
                        'fn_exim_export_oname',
                        '#key'
                    ),
                    'process_put' => array(
                        'fn_exim_set_oname',
                        '#key',
                        '#this',
                        '%Product SKU%',
                        $lang_code,
                        '%Product Name%',
                        '%List Price%',
                        '%Price%',
                        '%Deal Price%',
                        '%Quantity%',
                        '%Bar Code%',
                        $businessID
                    ),
                    'return_result' => true
                ),
                'Bar Code' => array(
                    'table' => 'product_options',
                    'db_field' => 'optionBarCode'
                ),
                'List Price' => array(
                    'table' => 'products_options_business',
                    'db_field' => 'productOptionProductPrice',
                    'required' => true
                ),
                'Price' => array(
                    'table' => 'products_options_business',
                    'db_field' => 'productOptionRegularPrice'
                ),
                'Deal Price' => array(
                    'table' => 'products_options_business',
                    'db_field' => 'dealPrice'
                ),
                'Quantity' => array(
                    'table' => 'product_options',
                    'db_field' => 'productOptionQuantity'
                ),
                'Measurement Length' => array(
                    'db_field' => 'measurementLength',
                    'required' => true,
                    'process_get' => array(
                        'fn_size_id_to_unit',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_unit_to_size'
                    ),
                    'return_result' => true
                ),
                'Measurement Weight' => array(
                    'db_field' => 'measurementWeight',
                    'required' => true,
                    'process_get' => array(
                        'fn_size_id_to_unit',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_unit_to_size'
                    ),
                    'return_result' => true
                ),
                'Box size' => array(
                    'process_get' => array(
                        'fn_exim_get_box_size',
                        '#key'
                    ),
                    'process_put' => array(
                        'fn_exim_put_box_size',
                        '#key',
                        '#this',
                        '%Product SKU%',
                        '%Product Name%'
                    ),
                    'linked' => false // this field is not linked during import-export
                ),
                'Business name' => array(
                    'linked' => false, // this field is not linked during import-export
                    'db_field' => 'businessID',
                    'required' => true,
                    'process_get' => array(
                        'fn_exim_export_bname',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_businessID',
                        '#key',
                        $businessID,
                        $lang_code,
                        '%URL Key%',
                        '%Product Name%'
                    ),
                    'return_result' => true
                ),
                'Brand' => array(
                    'db_field' => 'brandID',
                    'process_get' => array(
                        'fn_brand_id_to_name',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_brand_name_to_id'
                    ),
                    'return_result' => true
                ),
                'Category' => array(
                    'process_get' => array(
                        'fn_exim_get_product_categories',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_categories',
                        '#key',
                        '#this',
                        $lang_code,
                        '%URL Key%',
                        '%Product Name%'
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'required' => true,
                    'default' => 'Products' // default value applies only when we creating new record
                ),
//                'Status' => array(
//                    'db_field' => 'productStatus'
//                ),
                'Min Order Quantity' => array(
                    'db_field' => 'productMinBuyLimit'
                ),
                'Max Order Quantity' => array(
                    'db_field' => 'productMaxBuyLimit'
                ),
                'Start Date' => array(
                    'db_field' => 'productStartTime',
                    'process_get' => array(
                        'fn_timestamp_to_date',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_date_to_save'
                    ),
                    'return_result' => true
                ),
                'End Date' => array(
                    'db_field' => 'productEndTime',
                    'process_get' => array(
                        'fn_timestamp_to_date',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_date_to_save'
                    ),
                    'return_result' => true
                ),
                'Show days left' => array(
                    'db_field' => 'showCountTimer'
                ),
                'Prodct Deal' => array(
                    'db_field' => 'isProductDeal'
                ),
                'Deal Discount(%)' => array(
                    'db_field' => 'dealDiscount'
                ),
                'Deal Start Date' => array(
                    'db_field' => 'dealStartTime'
                ),
                'Deal End Date' => array(
                    'db_field' => 'dealEndTime'
                ),
                'Is Featured/Hot' => array(
                    'db_field' => 'featuredStatus'
                ),
                'Track Inventory' => array(
                    'db_field' => 'InventoryTrackLevel',
                    'process_get' => array(
                        'fn_track_to_label',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_label_to_track'
                    ),
                    'return_result' => true
                ),
                'Product Returnable' => array(
                    'db_field' => 'productReturnable',
                    'convert_put' => array(
                        'fn_return_to_default'
                    ),
                    'return_result' => true
                ),
                'Return Period' => array(
                    'db_field' => 'productReturnPeriod'
                ),
                'Dispatch Time' => array(
                    'db_field' => 'productDispatchTime',
                    'process_get' => array(
                        'fn_dispatch_id_to_time',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_time_to_dispatch_id'
                    ),
                    'return_result' => true
                ),
                'Admin Commission' => array(
                    'db_field' => 'productCommissionRate'
                ),
                'Service Fee' => array(
                    'db_field' => 'productServiceFee'
                ),
                'Status' => array(
                    'db_field' => 'productStatus',
                ),
                'Preview Image' => array(
                    'process_get' => array(
                        'fn_exim_get_image',
                        '#key'
                    ),
                    'convert_put' => array(
                        'fn_get_preview'
                    ),
                    'linked' => false,
                    'return_result' => true
                ),
                'Detailed image' => array(
                    'linked' => false,
                    'process_get' => array(
                        'fn_exim_get_main_image',
                        '#key'
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_main_import_images',
                        '@images_path',
                        '%Preview Image%',
                        '#key',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Tax Class' => array(
                    'db_field' => 'taxClassID',
                    'process_get' => array(
                        'fn_exim_get_taxes',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Tax Class ID' => array(
                    'process_get' => array(
                        'fn_exim_get_taxClassID',
                        '#key'
                    ),
                    'process_put' => array(
                        'fn_exim_set_taxClassID',
                        '#key',
                        '#this'
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'return_result' => true
                ),
                'Is tax payable to Merchant' => array(
                    'db_field' => 'taxPayableToBusiness'
                ),
                'Description' => array(
                    'table' => 'product_details',
                    'db_field' => 'productDescription',
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Short Description' => array(
                    'table' => 'product_details',
                    'db_field' => 'productShortDescription',
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Highlights' => array(
                    'table' => 'product_details',
                    'db_field' => 'productHighlights',
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Meta keyword' => array(
                    'table' => 'product_details',
                    'db_field' => 'productMetaKeywords'
                ),
                'Meta Description' => array(
                    'table' => 'product_details',
                    'db_field' => 'productMetaDescription'
                ),
                'Search Tags' => array(
                    'table' => 'product_details',
                    'db_field' => 'searchTags'
                ),
                'Product Name' => array(
                    'table' => 'product_details',
                    'db_field' => 'productTitle',
                    'required' => true,
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Meta Title' => array(
                    'table' => 'product_details',
                    'db_field' => 'productMetaTitle'
                ),
                'Multiple Options Available' => array(
                    'db_field' => 'multiOptionsAvailable'
                ),
                'Variants' => array(
                    'process_get' => array(
                        'fn_exim_get_product_variants',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_variants',
                        '#key',
                        '#this',
                        '%Multiple Options Available%',
                        $lang_code,
                        $businessID
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'return_result' => true
                ),
                /*'Custom Options' => array(
                    'process_get' => array(
                        'fn_exim_get_product_options',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_options',
                        '#key',
                        '#this',
                        $lang_code
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'return_result' => true
                ),*/
                'Attribute Set name' => array(
                    'process_get' => array(
                        'fn_exim_export_setname',
                        '#this'
                    ),
                    'convert_put' => array(
                        'fn_exim_set_attributeID'
                    ),
                    'db_field' => 'attributeSetID',
                    'required' => true // default value applies only when we creating new record
                ),
                /*'Attributes' => array(
                    'linked' => false,
                    'process_get' => array(
                        'fn_exim_get_product_attributes',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_attributes',
                        '#key',
                        '%Attribute Set name%',
                        '#this',
                        $lang_code
                    ),
                    'return_result' => true
                ),*/
                'Shipping Manage' => array(
                    'db_field' => 'shippingSetting'
                ),
                'Shipping Origin' => array(
                    'linked' => false,
                    'process_get' => array(
                        'fn_exim_get_shipping_origin',
                        '#key',
                        $businessID
                    ),
                    'process_put' => array(
                        'fn_exim_set_shipping_origin',
                        '#key',
                        '#this',
                        $businessID
                    ),
                    'return_result' => true
                ),
                'Shipping Info' => array(
                    'process_get' => array(
                        'fn_exim_get_product_shipping',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_shipping',
                        '#key',
                        '#this',
                        $lang_code
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'return_result' => true
                ),
               'Enable Size Chart' => array(
                    'db_field' => 'enableSizeChart',
                   'return_result' => true
                ), 
                'Size Chart' => array(
                    'db_field' => 'sizeChart',
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Sell As Batch' => array(
                    'db_field' => 'sellAsBatch',
                    'return_result' => true
                ),
                'Batch Type' => array(
                    'db_field' => 'batchType',
                    'return_result' => true
                ),
                'Quantity Per Batch' => array(
                    'db_field' => 'qtyPerBatch',
                    'return_result' => true
                ),
//                'ProductLock' => array(
//                  'db_field' => 'productLock',
//                  'linked' => false,
//                  'process_get' => array(
//                        'fn_exim_get_productlock',
//                        '%Status%'
//                    ),
//                'process_set' => array(
//                        'fn_exim_set_productlock',
//                        '#key',
//                        '#this',
//                    ),
//                'return_result' => true
//                ),
            )
        );
        return $schema;
    }
    public function getCombinationSchema($setID, $businessID = '',$lang_code='1') {
        //
        // Schema definition for Combinations
        //
        if (!empty($setID))
            $conditionArry = array(
                '&products.attributeSetID' => $setID,
                '&products.productStatus' => '!Deleted',
                'status' => '!D'
            );
        else
            $conditionArry = array(
                '&products.productStatus' => '!Deleted',
                'status' => '!D'
            );
        if (!empty($businessID))
            $conditionArry['&products.businessID'] = $businessID;
        $schema = array(
            'section' => 'products',
            'name' => 'product_combinations',
            'pattern_id' => 'product_combinations',
            'condition' => $conditionArry,
            'key' => array(
                'productID'
            ),
            'order' => 1,
            'table' => 'product_combination',
            'references' => array(
                'product_options' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'productOptionDefault' => 'Yes'
                    ),
                    'join_type' => 'LEFT'
                ),
                'products' => array(
                    'reference_fields' => array(
                        'productID' => '#key'
                    ),
                    'join_type' => 'LEFT'
                )
            ),
            'import_skip_db_processing' => true,
            'export_fields' => array(
                'Product ID' => array(
                    'required' => false,
                    'db_field' => 'productID'
                ),
                'Product SKU' => array(
                    'required' => true,
                    'db_field' => 'optionSKU',
                    'table' => 'product_options'
                ),
                'Combination SKU' => array(
                    'required' => true,
                    'alt_key' => true,
                    'db_field' => 'combinationSKU'
                ),
                'Bar Code' => array(
                    'required' => false,
                    'db_field' => 'combinationBarCode'
                ),
                'Combination' => array(
                    'required' => true,
                    'db_field' => 'combination',
                    'process_get' => array(
                        'fn_exim_get_product_combination',
                        '#this',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_put_product_combination',
                        '%Product SKU%',
                        '%Combination SKU%',
                        '#this',
                        '%Amount%',
                        '%Price Impact%',
                        '%Quantity%',
                        '#counter',
                        $lang_code,
                        '%Bar Code%',
                        '%Status%',
                        $businessID
                    )
                ),
                'Quantity' => array(
                    'required' => false,
                    'db_field' => 'combinationQty'
                ),
                'Amount' => array(
                    'required' => false,
                    'db_field' => 'combinationPrice'
                ),
                'Price Impact' => array(
                    'required' => false,
                    'db_field' => 'combinationPriceDiffType'
                ),
                'Status' => array(
                    'required' => false,
                    'db_field' => 'status'
                )
            )
        );
        return $schema;
    }
    public function getImagesSchema($setID, $businessID = '',$lang_code='1') {
        //
        // Schema definition for Images
        //
        if (!empty($setID))
            $conditionArry = array(
                '&products.attributeSetID' => $setID,
                '&products.productStatus' => 'Active',
                'productObjectType' => array(
                    'DO',
                    'C'
                )
            );
        else
            $conditionArry = array(
                '&products.productStatus' => 'Active',
                'productObjectType' => array(
                    'DO',
                    'C'
                )
            );
        if (!empty($businessID))
            $conditionArry['&products.businessID'] = $businessID;
        $schema = array(
            'section' => 'products',
            'name' => 'images',
            'pattern_id' => 'product_images',
            'condition' => $conditionArry,
            'key' => array(
                'productObjectID'
            ),
            'order' => 2,
            'table' => 'product_media',
            'references' => array(
                'products' => array(
                    'reference_fields' => array(
                        'productID' => '&productID'
                    ),
                    'join_type' => 'LEFT'
                )
            ),
            'options' => array(
                'images_path' => array(
                    'title' => 'images_directory',
                    'description' => 'text_images_directory',
                    'type' => 'input',
                    'default_value' => 'DIR_IMAGES' . 'backup'
                ),
                'remove_images' => array(
                    'title' => 'exim_remove_additional_images',
                    'description' => 'text_remove_additional_images',
                    'type' => 'checkbox',
                    'import_only' => true
                )
            ),
            'import_skip_db_processing' => true,
            'export_fields' => array(
                'Product ID' => array(
                    'db_field' => 'productID'
                ),
                'Product Name' => array(
                    'process_get' => array(
                        'fn_exim_get_product_name',
                        '$Product ID',
                        $lang_code
                    ),
                    'linked' => false,
                    'return_result' => true
                ),
                'Pair type' => array(
                    'db_field' => 'productObjectType',
                    'required' => true
                ),
                'SKU' => array(
                    'required' => true,
                    'process_get' => array(
                        'fn_exim_get_object_sku',
                        '#key',
                        '$Pair type'
                    ),
                    'linked' => false,
                    'return_result' => true
                ),
                'Preview Image' => array(
                    'process_get' => array(
                        'fn_exim_get_mimage',
                        '$Detailed image',
                        '$Pair type'
                    ),
                    'convert_put' => array(
                        'fn_get_preview'
                    ),
                    'linked' => false,
                    'required' => true,
                    'return_result' => true
                ),
                'Detailed image' => array(
                    'process_put' => array(
                        'fn_exim_set_import_image',
                        '@images_path',
                        '%Preview Image%',
                        '#key',
                        '#this',
                        '%SKU%',
                        '%Pair type%',
                        $businessID
                    ),
                    'db_field' => 'productMedia',
                    'required' => true
                )
            )
        );
        return $schema;
    }
    public function getCustomOptionsSchema($setID, $businessID = '', $lang_code='1') {
        //
        // Schema definition for Product Attributes
        //		
        
        $timeZone         = '';
        $default_currency = '';
        $status			  = '';
       
        if (!empty($setID))
            $conditionArry = array(
                'attributeSetID' => $setID,
                'productStatus' => '!Deleted'
            );
        else
            $conditionArry = array(
                'productStatus' => '!Deleted'
            );
        if (!empty($businessID))
            $conditionArry['&products.businessID'] = $businessID;        
        $schema = array(
            'section' => 'products',
            'name' => 'products',
            'pattern_id' => 'products',
            'key' => array(
                'productID'
            ),
            'order' => 0,
            'table' => 'products',
            'alt_table' => 'product_options',
            'alt_table_key' => 'productID',
            'alt_condition' => array(
                'productOptionStatus' => '!Delete',
                'businessID' => $businessID
            ),
            'condition' => $conditionArry,
            'references' => array(
                'product_details' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'languageID' => $lang_code
                    ),
                    'join_type' => 'LEFT'
                ),
                'product_options' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'productOptionDefault' => 'Yes'
                    ),
                    'join_type' => 'LEFT'
                )
            ),
            
            'export_fields' => array(
                'Product ID' => array(
                    'process_get' => array(
                        'fn_exim_get_key',
                        '#key'
                    ),
                    'linked' => false
                ),               
                'Product SKU' => array(
                    'table' => 'product_options',
                    'db_field' => 'optionSKU',
                    'required' => true,
                    'alt_key' => true
                ),
                'Business name' => array(
                    'linked' => false, // this field is not linked during import-export
                    'db_field' => 'businessID',                    
                    'process_get' => array(
                        'fn_exim_export_bname',
                        '#key',
                        $lang_code
                    ),                    
                    'return_result' => true
                ),      
                'Product Name' => array(
                    'process_get' => array(
                        'fn_exim_get_product_name',
                        '#key',
                        $lang_code
                    ),
                    'linked' => false,
                    'return_result' => true
                ),
                 'Custom Options' => array(
                    'process_get' => array(
                        'fn_exim_get_product_options',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_options',
                        '#key',
                        '#this',
                        $lang_code
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'return_result' => true
                ),
                
                
            )
        );
        return $schema;
    }
    public function getCustomOptionsSchemaOld($setID, $businessID = '',$lang_code='1') {
        //
        // Schema definition for Combinations
        //
       
        if (!empty($setID))
            $conditionArry = array(
                '&products.attributeSetID' => $setID,
                '&products.productStatus' => '!Deleted'
            );
        else
            $conditionArry = array(
                '&products.productStatus' => '!Deleted'
            );
        if (!empty($businessID))
            $conditionArry['&products.businessID'] = $businessID;
        $schema = array(
            'section' => 'products',
            'name' => 'product_attributes',
            'pattern_id' => 'product_attributes',
            'condition' => $conditionArry,
            'key' => array(
                'productID'
            ),
            'order' => 1,
            'table' => 'product_custom_option_link',
            'references' => array(
                                
                'products' => array(
                    'reference_fields' => array(
                        'productID' => '#key'
                    ),
                    'join_type' => 'LEFT'
                ),
                'product_custom_option' => array(
                    'reference_fields' => array(
                        'customOptionID' => '&customOptionID',
                        'status' => '!D'
                    ),
                    'join_type' => 'LEFT'
                )
            ),
            'import_skip_db_processing' => true,
            'export_fields' => array(
                'Product ID' => array(
                    'required' => false,
                    'db_field' => 'productID'
                ),
               
                'Product SKU' => array(
                    'required' => true,
                    'db_field' => 'optionSKU',
                    'table' => 'product_options'
                ),
                'Custom Options' => array(
                    'process_get' => array(
                        'fn_exim_get_product_options',
                        '#key',
                        $lang_code
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_options',
                        '#key',
                        '#this',
                        $lang_code
                    ),
                    'linked' => false, // this field is not linked during import-export
                    'return_result' => true
                )
            )
        );
        return $schema;
    }
    public function getAttributesSchema($setID, $businessID = '', $lang_code='1') {
        //
        // Schema definition for Product Attributes
        //		
        
        $timeZone         = '';
        $default_currency = '';
        $status			  = '';
       
        if (!empty($setID))
            $conditionArry = array(
                'attributeSetID' => $setID,
                'productStatus' => '!Deleted'
            );
        else
            $conditionArry = array(
                'productStatus' => '!Deleted'
            );
        if (!empty($businessID))
            $conditionArry['&products.businessID'] = $businessID;        
        $schema = array(
            'section' => 'products',
            'name' => 'products',
            'pattern_id' => 'products',
            'key' => array(
                'productID'
            ),
            'order' => 0,
            'table' => 'products',
            'alt_table' => 'product_options',
            'alt_table_key' => 'productID',
            'alt_condition' => array(
                'productOptionStatus' => '!Delete',
                'businessID' => $businessID
            ),
            'condition' => $conditionArry,
            'references' => array(
                'product_details' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'languageID' => $lang_code
                    ),
                    'join_type' => 'LEFT'
                ),
                'product_options' => array(
                    'reference_fields' => array(
                        'productID' => '#key',
                        'productOptionDefault' => 'Yes'
                    ),
                    'join_type' => 'LEFT'
                )
            ),
            
            'export_fields' => array(
                'Product ID' => array(
                    'process_get' => array(
                        'fn_exim_get_key',
                        '#key'
                    ),
                    'linked' => false
                ),               
                'Product SKU' => array(
                    'table' => 'product_options',
                    'db_field' => 'optionSKU',
                    'required' => true,
                    'alt_key' => true
                ),
                'Business name' => array(
                    'linked' => false, // this field is not linked during import-export
                    'db_field' => 'businessID',                    
                    'process_get' => array(
                        'fn_exim_export_bname',
                        '#key',
                        $lang_code
                    ),                    
                    'return_result' => true
                ),      
                'Product Name' => array(
                    'process_get' => array(
                        'fn_exim_get_product_name',
                        '#key',
                        $lang_code
                    ),
                    'linked' => false,
                    'return_result' => true
                ),
                'Attributes' => array(
                    'linked' => false,
                    'process_get' => array(
                        'fn_exim_get_product_attributes',
                        '#key',
                        $lang_code,
                        $setID
                    ),
                    'process_put' => array(
                        'fn_exim_set_product_attributes',
                        '#key',
                        '%Attribute Set name%',
                        '#this',
                        $lang_code
                    ),
                    'return_result' => true
                ),
                
            )
        );
        return $schema;
    }    
    public function getBrandSchema($lang_code='1') { //
        // Schema definition for Brands
        //
        $schema = array(
            'section' => 'brands',
            'name' => 'brands',
            'pattern_id' => 'brands',
            'key' => array(
                'brandID'
            ),
            'order' => 0,
            'table' => 'brands',
            'alt_table' => 'brand_details',
            'alt_table_key' => 'brandID',
            'alt_condition' => array(
                'status' => '!D'
            ),
            'condition' => array(),
            'references' => array(
                'brand_details' => array(
                    'reference_fields' => array(
                        'brandID' => '#key',
                        'languageID' => $lang_code
                    ),
                    'join_type' => 'LEFT'
                )
            ),
            'post_processing' => array(),
            'notes' => array(
                'text_exim_import_options_note',
                'text_exim_import_features_note',
                'text_exim_import_images_note',
                'text_exim_import_files_note'
            ),
            'options' => array(
                'images_path' => array(
                    'title' => 'images_directory',
                    'description' => 'text_images_directory',
                    'type' => 'input',
                    'default_value' => 'DIR_IMAGES' . 'backup'
                ),
                'files_path' => array(
                    'title' => 'files_directory',
                    'description' => 'text_files_directory',
                    'type' => 'input',
                    'default_value' => 'DIR_DOWNLOADS' . 'backup'
                )
            ),
            'export_fields' => array(
                'Brand ID' => array(
                    'process_get' => array(
                        'fn_exim_get_key',
                        '#key'
                    ),
                    'linked' => false
                ),
                'Brand Key' => array(
                    'db_field' => 'brandKey',
                    'process_put' => array(
                        'fn_create_key',
                        '%Brand Name%',
                        '#key'
                    ),
                    'return_result' => true
                ),
                'Status' => array(
                    'db_field' => 'status'
                ),
                'Brand Icon' => array(
                    'process_put' => array(
                        'fn_exim_set_brand_image',
                        '@images_path',
                        '#key',
                        '#this'
                    ),
                    'linked' => false,
                    'return_result' => true
                ),
                'Brand Name' => array(
                    'table' => 'brand_details',
                    'db_field' => 'brandName',
                    'alt_key' => true,
                    'required' => true,
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                ),
                'Brand Description' => array(
                    'table' => 'brand_details',
                    'db_field' => 'brandDescription',
                    'process_get' => array(
                        'fn_html_entity_decode',
                        '#this'
                    ),
                    'return_result' => true
                )
            )
        );
        return $schema;
    }
    /* function delete($pattern)
    {
    $primary_key = $pattern['key'];
    $table_fields = $primary_key;
    $joins = array();
    $processes = array();
    $conditions = array();
    
    // Add delete conditions
    if (!empty($pattern['condition'])) {
    $_cond = array();
    $_set = array();
    foreach ($pattern['condition'] as $field => $value) {
    
    //check the field is primary for deleting 
    if (strpos($field, '#') !== false) {
    $field = substr($field, 1);
    
    //find the values (single or multiple)
    if (is_array($value)) {
    $_val = implode("','", $value);
    } else if (strpos($value, '@') !== false) {
    $_opt = str_replace('@', '', $value);
    $_val = $options[$_opt];
    } else {
    $_val = $value;
    }
    
    $_cond[] = $field." IN ('".$_val."')";
    }
    else if(strpos($field, '!') !== false) {
    $field = substr($field, 1);
    $_set[]= $field. " = 'Deleted'";
    }
    }
    
    $conditions[] = implode(' AND ', $_cond);
    $setUpdate = implode(' , ', $_set);
    }
    $queries[] =   "UPDATE  " .DB_PREFIX. $pattern['table'] .' SET '. $setUpdate . (!empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : '');	
    foreach($queries as $query){
    $this->ObjDatabase->setQuery($query);
    }
    
    } */
    //
    // Export data using pattern
    // Parameters:
    // @pattern - import/export pattern
    // @export_fields - export defined fields only
    // @options - export options
    // @exportTo - export to csv or API
    // FIXME: add export conditions
    function export($pattern, $export_fields, $options, $extras = array()) {
        
        extract($extras);
        $resourceAccess = isset($resourceAccess) ? $resourceAccess : '';
        if ($resourceAccess == 'all') {
            $export_fields = array_keys($pattern['export_fields']);
        }
        if (isset($options)) {
            $fields_names = $export_fields;
        }
        $primary_key = $pattern['key'];
        if (sizeof($primary_key) == 1)
            $primary_key[0] = $pattern['table'] . '.' . $primary_key[0];
        $table_fields = $primary_key;
        $exportFields = array();
        $joins        = array();
        $processes    = array();
        $conditions   = array();
        
        // Build list of fields that should be retrieved from the database
        //echo "<pre>";print_r($pattern);exit;
        foreach ($pattern['export_fields'] as $field => $data) {
            if (!in_array($field, $export_fields)) {
                continue;
            }
            $exportFields[] = isset($data['db_field']) ? $data['db_field'] : '';
            // Do no link this field
            if (isset($data['linked']) && $data['linked'] == false) {
                // do something?
            }
            // Primary object table
            elseif (empty($data['table']) || $data['table'] == $pattern['table']) {
                $table_fields[] = $pattern['table'] . '.' . (!empty($data['db_field']) ? $data['db_field'] . ' as "' . $field . '"' : $field);
                // Linked object tables
            } else {
                $table_fields[] = $data['table'] . '.' . (!empty($data['db_field']) ? $data['db_field'] . ' as "' . $field . '"' : $field);
            }
            
            if (!empty($data['process_get'])) {
                $processes[$field]['function'] = array_shift($data['process_get']);
                if (is_object($data['process_get'][0])) {
                    $processes[$field]['object'] = array_shift($data['process_get']);
                } else {
                    $processes[$field]['object'] = $this;
                }
                $processes[$field]['args'] = $data['process_get'];
            }
        }
        // Build the list of joins
        if (!empty($pattern['references'])) {
            foreach ($pattern['references'] as $table => $data) {
                $ref = array();
                foreach ($data['reference_fields'] as $k => $v) {
                    if (strval($v) == 'key' || strval($v) == '#key') {
                        $_val = (sizeof($primary_key) == 1) ? reset($primary_key) : '';
                    } elseif (substr($v, 0, 1) == '&') {
                        $_val = $pattern['table'] . '.' . substr($v, 1);
                    } elseif (strpos($v, '@') !== false) {
                        $_opt = str_replace('@', '', $v);
                        $_val = "'" . $options[$_opt] . "'";
                    } elseif (substr($v, 0, 1) == '%') {
                        $_val = $pattern['ref_table'] . '.' . substr($v, 1);
                    } elseif (substr($v, 0, 1) == '~') {
                        $_val = substr($v, 1);
                    } else {
                        $_val = "'$v'";
                    }
                    $ref[] = "$table.$k = $_val";
                }
                $joins[] = $data['join_type'] . ' JOIN ' . DB_PREFIX . $table . " as $table ON " . implode(' AND ', $ref);
            }
        }
       
        // Add retrieve conditions
        if (!empty($pattern['condition']) && !empty($exportFields)) {
            $_cond = array();
            foreach ($pattern['condition'] as $field => $value) {
                
                if (is_array($value)) {
                    if (in_array($field, $exportFields)) {
                        $filter = array_keys($value);
                        //isset added
                        if (isset($pattern['export_fields'][$field]['table'])) {
                            $field = $pattern['export_fields'][$field]['table'] . "." . $field;
                        } else if ((isset($pattern['export_fields'][$field]['alt_key']))) {
                            $field = $pattern['table'] . "." . $field;
                        }
                        //isset added
                        if ($filter[0] === 'eq') {
                            $_val    = $value['eq'];
                            $_cond[] = $field . "='" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'neq') {
                            $_val    = $value['neq'];
                            $_cond[] = $field . "!='" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'lt') {
                            $_val    = $value['lt'];
                            $_cond[] = $field . "<'" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'gt') {
                            $_val    = $value['gt'];
                            $_cond[] = $field . ">'" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'lteq') {
                            $_val    = $value['lteq'];
                            $_cond[] = $field . "<='" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'gteq') {
                            $_val    = $value['gteq'];
                            $_cond[] = $field . ">='" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'in') {
                            $_val    = "'".$value['in']."'";
                            $_val    = $value['in'];
                            $_cond[] = $field . " in (" . $_val . ")";
                            continue;
                        } else if ($filter[0] === 'nin') {
                            $_val    = $value['nin'];
                            $_cond[] = $field . " not in (" . $_val . ")";
                            continue;
                        } else if ($filter[0] === 'llike') {
                            $_val    = $value['llike'];
                            $_cond[] = $field . " like '%" . $_val . "'";
                            continue;
                        } else if ($filter[0] === 'rlike') {
                            $_val    = $value['rlike'];
                            $_cond[] = $field . " like '" . $_val . "%'";
                            continue;
                        } else if ($filter[0] === 'like') {
                            $_val    = $value['like'];
                            $_cond[] = $field . " like '%" . $_val . "%'";
                            continue;
                        }
                    } else {
                        $errorArray = array(
                            'error' => $field,
                            'errType' => 'filterKey'
                        );
                        $this->reportError($errorArray);
                    }
                    $_val = implode("','", $value);
                } elseif (strpos($value, '@') !== false) {
                    $_opt = str_replace('@', '', $value);
                    $_val = $options[$_opt];
                } else {
                    $_val = $value;
                }
                if (strpos($field, '#') !== false) {
                    $field = substr($field, 1);
                }
                if (strpos($field, '!') !== false) {
                    $field = substr($field, 1);
                }
                if (strpos($field, '&') !== false) {
                    $_field = substr($field, 1);
                } else {
                    $_field = $pattern['table'] . '.' . $field;
                }
                if (strpos($_val, '!') !== false) {
                    $_val    = str_replace('!', '', $_val);
                    $_cond[] = "$_field !='$_val'";
                } else {
                        if($_field == 'products.productID')
                            $_cond[] = "$_field IN ($_val)";
                        else
                            $_cond[] = "$_field IN ('$_val')";
                }
            }
            $conditions[] = implode(' AND ', $_cond);
        }
        if (empty($extras)) {
            $limitFrom = $options['limitFrom'];
            $limitTo   = $options['limitTo'];
            if (empty($limitFrom) && empty($limitTo)) {
                // Build main query
                $query         = "SELECT " . implode(', ', $table_fields) . " FROM " . DB_PREFIX . $pattern['table'] . " as " . $pattern['table'] . ' ' . implode(' ', $joins) . (!empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : ''); 
                //echo $query; exit;
                $total         = $this->ObjDatabase->numberOfRecords("SELECT COUNT(*) FROM " . DB_PREFIX . $pattern['table'] . " as " . $pattern['table'] . ' ' . implode(' ', $joins) . (!empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : ''));
                
                $step          = 50; // define number of rows to get from database
                $iterator      = 0; // start retrieving from
                $data_exported = false;
                $attrArray = array();
                while ($data = $this->ObjDatabase->readValues($query . " LIMIT $iterator, $step")) {
                    $data_exported = true;
                    $result        = array();
                    foreach ($data as $k => $v) {
                        $result[$k] = $this->fn_array_key_intersect($v, $pattern['export_fields']);
                        
                        foreach ($processes as $field => $process_data) {
                            $args = array();
                            foreach ($process_data['args'] as $ak => $av) {
                                if (is_object($av)) {
                                    $args[$ak] = $av;
                                } else {
                                    if ($av === '#this') {
                                        $args[$ak] = $v[$field];
                                    } elseif ($av === '#key') {
                                        $args[$ak] = (sizeof($pattern['key']) == 1) ? $v[reset($pattern['key'])] : '';
                                    } elseif (strpos($av, '@') !== false) {
                                        $_opt      = str_replace('@', '', $av);
                                        $args[$ak] = $options[$_opt];
                                    } elseif (strpos($av, '$') !== false) {
                                        $_opt      = str_replace('$', '', $av);
                                        $args[$ak] = $v[$_opt];
                                    } elseif ($av === '#field') {
                                        $args[$ak] = $field;
                                    } else {
                                        $args[$ak] = $av;
                                    }
                                }
                            }
                            $args['export_fields'] = $export_fields;
                            $result[$k][$field]    = call_user_func_array(array(
                                $process_data['object'],
                                $process_data['function']
                            ), $args);
                        }
                    }
                    
                    // Sort result array
                    $_result = array();
                    foreach ($result as $k => $v) {
                       
                         foreach ($export_fields as $field) {
                            if($options['pattern_id']=='product_custom_options') {                                
                                if(is_array($field)) {                                    
                                    break;
                                }
                            }                    
                            if (in_array($field, array_keys($pattern['export_fields']))) {
                                if(($field=='Attributes' && $options['pattern_id']=='product_attributes') || ($field=='Custom Options' && $options['pattern_id']=='product_custom_options')) {
                                                                        
                                    if(!empty($export_fields[$field])) {   
                                        
                                        $attrs = !empty($v[$field])?array_keys($v[$field]):array();                                        
                                        foreach($export_fields[$field] as $fkey=>$fld) {                                         
                                            if(in_array($fkey, $attrs) && !empty($attrs)) {                                                
                                                if($field=='Custom Options' && $options['pattern_id']=='product_custom_options') {
                                                    $_result[$k][$fld] = $v[$field][$fkey];
                                                } else {
                                                    $sp = explode(":",$v[$field][$fkey]);  
                                                    if(!empty($sp)) {
                                                        unset($sp[0]);
                                                        $splitValue = '';
                                                        foreach($sp as $split) {
                                                            $splitValue = ($splitValue=='') ? $split:$splitValue.":".$split;
                                                        }                                
                                                    }
                                                    $_result[$k][$fld] = $splitValue;
                                                }   
                                                
                                            } else {                                                   
                                                $_result[$k][$fld] = '';                                                
                                             }
                                            
                                        }
                                        
                                    } else {
                                        if (isset($fields_names[$field])) {
                                            $_result[$k][$fields_names[$field]] = $v[$field];
                                        } else { //isset edited
                                            $_result[$k][$field] = (isset($v[$field])) ? $v[$field] : '';
                                        }
                                    }
                                } else { 
                                    if (isset($fields_names[$field])) {
                                        $_result[$k][$fields_names[$field]] = $v[$field];
                                    } else { //isset edited
                                        $_result[$k][$field] = (isset($v[$field])) ? $v[$field] : '';
                                    }
                                }
                            }
                        }
                        
                    }
                    unset($result);
                    // Put data
                    $enclosure = (isset($pattern['enclosure'])) ? $pattern['enclosure'] : '"';
                    $this->fn_put_csv($_result, $options, $enclosure);
                    unset($_result);
                    $iterator += $step;
                }
            } else {                
                //Export Within Limits
                // Build main query
                $query         = "SELECT " . implode(', ', $table_fields) . " FROM " . DB_PREFIX . $pattern['table'] . " as " . $pattern['table'] . ' ' . implode(' ', $joins) . (!empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : '');
                
                $total         = $this->ObjDatabase->numberOfRecords("SELECT COUNT(*) FROM " . DB_PREFIX . $pattern['table'] . " as " . $pattern['table'] . ' ' . implode(' ', $joins) . (!empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : ''));
                $step          = 30; // define number of rows to get from database
                $iterator      = $start = $limitFrom - 1; // start retrieving from
                $data_exported = false;
                $flag          = 0;
                if (($start + $step) > $limitTo) {
                    $step = $limitTo - $start;
                    $flag = 1;
                }
                while ($data = $this->ObjDatabase->readValues($query . " LIMIT $start, $step")) {
                    $data_exported = true;
                    $result        = array();
                    foreach ($data as $k => $v) {
                        $result[$k] = $this->fn_array_key_intersect($v, $pattern['export_fields']);
                        foreach ($processes as $field => $process_data) {
                            $args = array();
                            foreach ($process_data['args'] as $ak => $av) {
                                if (is_object($av)) {
                                    $args[$ak] = $av;
                                } else {
                                    if ($av === '#this') {
                                        $args[$ak] = $v[$field];
                                    } elseif ($av === '#key') {
                                        $args[$ak] = (sizeof($pattern['key']) == 1) ? $v[reset($pattern['key'])] : '';
                                    } elseif (strpos($av, '@') !== false) {
                                        $_opt      = str_replace('@', '', $av);
                                        $args[$ak] = $options[$_opt];
                                    } elseif (strpos($av, '$') !== false) {
                                        $_opt      = str_replace('$', '', $av);
                                        $args[$ak] = $v[$_opt];
                                    } elseif ($av === '#field') {
                                        $args[$ak] = $field;
                                    } else {
                                        $args[$ak] = $av;
                                    }
                                }
                            }
                            $args['export_fields'] = $export_fields;
                            $result[$k][$field]    = call_user_func_array(array(
                                $process_data['object'],
                                $process_data['function']
                            ), $args);
                        }
                    }
                    // Sort result array
                    $_result = array();                   
                    foreach ($result as $k => $v) {
                        foreach ($export_fields as $field) {
                            if (in_array($field, array_keys($pattern['export_fields']))) {
                                if (isset($fields_names[$field])) {
                                    $_result[$k][$fields_names[$field]] = $v[$field];
                                } else { //isset edited
                                    $_result[$k][$field] = (isset($v[$field])) ? $v[$field] : '';
                                }
                            }
                        }
                    }
                    unset($result);
                    // Put data
                    $enclosure = (isset($pattern['enclosure'])) ? $pattern['enclosure'] : '"';
                    $this->fn_put_csv($_result, $options, $enclosure);
                    unset($_result);
                    $start = $start + $step;
                    if (($start + $step) > $limitTo) {
                        $step = $limitTo - $start;
                    }
                    if ($step <= 0 || $flag == 1) {
                        break;
                    }
                }
            }
            $this->fn_get_file(__DIR_EXIM . $options['filename'], $options['filename']);
            exit;
        } else if (!empty($exportFields)) {
            // Build main query
            $query = "SELECT " . implode(', ', $table_fields) . " FROM " . DB_PREFIX . $pattern['table'] . " as " . $pattern['table'] . ' ' . implode(' ', $joins) . (!empty($conditions) ? ' WHERE ' . implode(' AND ', $conditions) : '');
            
            if (!in_array($pattern['order'], $exportFields)) {
                $errorArray = array(
                    'error' => $pattern['order'],
                    'errType' => 'order'
                );
                $this->reportError($errorArray);
            }
            if (!in_array($pattern['dir'], array(
                'desc',
                'asc',
                'ASC',
                'DESC'
            )) && $pattern['dir']) {
                $errorArray = array(
                    'error' => $pattern['dir'],
                    'errType' => 'dir'
                );
                $this->reportError($errorArray);
            }
            if ($pattern['limit'] != '') {
                if ((int) $pattern['limit'] >= 0) {
                    $pattern['limit'] = (int) $pattern['limit'];
                }
            }
            if ($pattern['order'] != '') {
                $query .= " ORDER BY " . $pattern['order'] . " " . $pattern['dir'] . "";
            }
            if ($pattern['limit'] != '') {
                $query .= " LIMIT " . $pattern['limit'] . "";
            } else if ($pattern['from'] != '' && $pattern['to'] != '') {
                $query .= " LIMIT " . $pattern['from'] . "," . $pattern['to'] . "";
            }
            if ($this->hasError()) {
                $this->showErrors();
            } else {
                $data = $this->ObjDatabase->readValues($query);
            }
            $result = array();
            foreach ($data as $k => $v) {
                $result[$k] = $this->fn_array_key_intersect($v, $pattern['export_fields']);
                foreach ($processes as $field => $process_data) {
                    $args = array();
                    foreach ($process_data['args'] as $ak => $av) {
                        if (is_object($av)) {
                            $args[$ak] = $av;
                        } else {
                            if ($av === '#this') {
                                $args[$ak] = $v[$field];
                            } elseif ($av === '#key') {
                                $args[$ak] = (sizeof($pattern['key']) == 1) ? $v[reset($pattern['key'])] : '';
                            } elseif (strpos($av, '@') !== false) {
                                $_opt      = str_replace('@', '', $av);
                                $args[$ak] = $options[$_opt];
                            } elseif (strpos($av, '$') !== false) {
                                $_opt      = str_replace('$', '', $av);
                                $args[$ak] = $v[$_opt];
                            } elseif ($av === '#field') {
                                $args[$ak] = $field;
                            } else {
                                $args[$ak] = $av;
                            }
                        }
                    }
                    $args['export_fields'] = $export_fields;
                    $result[$k][$field]    = call_user_func_array(array(
                        $process_data['object'],
                        $process_data['function']
                    ), $args);
                }
            }
            $_response = $result;
            return $this->output($_response, $responseType);
        } else {
            $errorArray = array(
                'errType' => 'resource_restricted'
            );
            $this->reportError($errorArray);
            if ($this->hasError()) {
                $this->showErrors();
            }
        }
    }
    //
    // Put data to csv file
    // Parameters:
    // @data - export data
    // @options - options
    function fn_put_csv(&$data, &$options, $enclosure) {
        static $output_started = false;
        $eol       = "\n";
        $delimiter = ',';
        //fn_mkdir(__DIR_EXIM);
        
        foreach ($data as $k => $v) {
            foreach ($v as $name => $value) {
                $data[$k][$name] = $enclosure . str_replace(array(
                    "\r",
                    "\n",
                    "\t",
                    $enclosure
                ), array(
                    '',
                    '',
                    '',
                    $enclosure . $enclosure
                ), $value) . $enclosure;
            }
        }
        if ($output_started == false || isset($options['force_header'])) {
            $fields = array_keys($data[0]);
        } else {
            $fields = '';
        }
        $export_data = $data;
        $csv         = '';
        if ($fields)
            $csv = implode($delimiter, $fields) . $eol;
        foreach ($export_data as $data) {
            $csv .= implode($delimiter, $data) . $eol;
        }
        $fd = fopen(__DIR_EXIM . $options['filename'], ($output_started && !isset($options['force_header'])) ? 'ab' : 'wb');
        if ($fd) {
            fwrite($fd, $csv, strlen($csv));
            fclose($fd);
            @chmod(__DIR_EXIM . $options['filename'], 0666);
        }
        if ($output_started == false) {
            $output_started = true;
        }
        unset($options['force_header']);
        return true;
    }
    //
    // ------------- Utility functions ---------------
    /**
     * Creates categories tree by path
     *
     * @param integer $product_id Product ID
     * @param string $link_type M - main category, A - additional
     * @param string $categories_data categories path
     * @param string $category_delimiter Delimiter in categories path
     * @param string $lang_code Two-letters language code
     * @param string $store_name Store name (is used for saving category company_id)
     * @return boolean True if any categories were updated.
     */
    function fn_exim_set_product_categories($product_id, $categories_data, $lang_code = 1, $productUrl = '', $productName = '') {
        $category_delimiter = '///';
        //URL Rewrite
        if (empty($productUrl) || $productUrl == '') {
            $productUrl = $this->ObjDatabase->getField("SELECT productUrl FROM " . DB_PREFIX . "products WHERE productID='" . $product_id . "'");
            if (empty($productUrl) || $productUrl == '') {
                $productUrl = $this->fn_generate_productUrl($productName);
                $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET productUrl='" . $productUrl . "' WHERE productID ='" . $product_id . "'");
            }
        }
        $productUrl = strtolower($productUrl);
        $this->fn_insert_basic_rewrite_details($product_id, $productUrl, '');
        $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_to_category WHERE productID ='" . $product_id . "'");
        $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "url_rewrite WHERE objectID = " . $product_id . " AND type='product' AND parentID <> 0 ");
        if (empty($categories_data)) {
            return false;
        }
        $set_delimiter      = ';';
        $paths              = array();
        $updated_categories = array();
        // Check if array is provided
        if (strpos($categories_data, $set_delimiter) !== false) {
            $paths = explode($set_delimiter, $categories_data);
            array_walk($paths, array(
                $this,
                'fn_trim_helper'
            ));
        } else {
            $paths[] = $categories_data;
        }
        if (!$this->fn_is_empty($paths)) {
            $old_data = $this->ObjDatabase->readValues("SELECT * FROM " . DB_PREFIX . "product_to_category WHERE productID='" . $product_id . "'");
            foreach ($old_data as $k => $v) {
                $updated_categories[] = $k;
            }
            //$this->ObjDatabase->setQuery("DELETE FROM ".DB_PREFIX."product_to_category WHERE productID ='".$product_id."'");
        }
        foreach ($paths as $category) {
            $categories = (strpos($category, $category_delimiter) !== false) ? explode($category_delimiter, $category) : array(
                $category
            );
            if (!empty($categories)) {
                $parent_id = '0';
                foreach ($categories as $cat) {
                    //$this->fn_html_entity_encode($cat)
                    $category_condition = '';
                    $category_ids       = $this->ObjDatabase->readValue("SELECT " . DB_PREFIX . "product_category_details.productCategoryID FROM " . DB_PREFIX . "product_category_details INNER JOIN " . DB_PREFIX . "product_categories ON
										     " . DB_PREFIX . "product_categories.productCategoryID = " . DB_PREFIX . "product_category_details.productCategoryID $category_condition
								    WHERE " . DB_PREFIX . "product_categories.productCategoryStatus!='Delete' AND " . DB_PREFIX . "product_category_details.productCategoryName ='" . $cat . "' AND languageID = '" . $lang_code . "' AND productCategoryParent='" . $parent_id . "'");
                    $category_id        = $category_ids['productCategoryID'];
                    if (!empty($category_id)) {
                        $parent_id = $category_id;
                    }
                }
                $data = array(
                    'productID' => $product_id,
                    'productCategoryID' => $category_id
                );
                if (!empty($old_data) && !empty($old_data[$category_id])) {
                    $data = array_merge($old_data[$category_id], $data);
                }
                $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "product_to_category(`productID`,`productCategoryID`) VALUES('" . $product_id . "', '" . $category_id . "')");
                $updated_categories[] = $category_id;
                //URL REWRITE
                $this->fn_insert_basic_rewrite_details($product_id, $productUrl, $category_id);
            }
        }
        //exit;
        if (!empty($updated_categories)) {
            return true;
        }
        return false;
    }
    //
    // Export product categories
    // Parameters:
    // @product_id - product ID
    // @link_type - M - main category, A - additional
    // @delimter - path delimiter
    // @lang_code - language code
    /*function fn_exim_get_product_categories($product_id,$lang_code = '')
    {
    $languageIDs['Current']=$languageIDs['Default']=$lang_code;
    $ObjProduct 	  = new ProductModel();
    $resProductcategory 	  = $ObjProduct->listProductTocategoryDetails($languageIDs,$product_id,"All");	
    $set_delimiter = ';';
    $result = array();
    foreach ($resProductcategory as $category) {
    $parent='';
    if($category['parentCategory']!='')
    {
    $supercategory_ids = $this->ObjDatabase->readValue("SELECT productCategoryParent FROM ".DB_PREFIX."product_categories 
    WHERE productCategoryID ='".$category['productCategoryParent']."'");
    if ($supercategory_ids['productCategoryParent']!=0)
    {
    
    $supercategory_names=$this->ObjDatabase->readValue("SELECT ".DB_PREFIX."product_category_details.productCategoryName FROM ".DB_PREFIX."product_category_details 
    WHERE   languageID = '".$lang_code."' AND productCategoryID='".$supercategory_ids['productCategoryParent']."'");	
    
    if(!empty($supercategory_names['productCategoryName']))
    {
    $parent.=$this->fn_html_entity_decode($supercategory_names['productCategoryName'])."///";	
    }
    }
    
    $parent.=$this->fn_html_entity_decode($category['parentCategory'])."///";
    }
    $result[] = $parent.$this->fn_html_entity_decode($category['productCategoryName']);
    }
    return implode($set_delimiter, $result);
    }*/
    //
    // Export product categories
    // Parameters:
    // @product_id - product ID
    // @link_type - M - main category, A - additional
    // @delimter - path delimiter
    // @lang_code - language code
    function fn_exim_export_bname($product_id, $lang_code) {
        $ObjProduct = new ProductModel();
        $bname      = $ObjProduct->getMerchantNameByProductID($product_id, $lang_code);
        return $this->fn_html_entity_decode($bname);
    }
    function fn_exim_export_setname($setID) {
        $ObjAttr = new AttributeModel();
        $set     = $ObjAttr->getAttributeSetDetails($setID);
        return $this->fn_html_entity_decode($set['attributeSetName']);
    }
    //
    // Converts timestamp to human-readable date
    //
    function fn_timestamp_to_date($timestamp) {
        if ($timestamp == '0000-00-00')
            return '';
        else {
            $timestamp = date("d-m-Y", strtotime($timestamp));
        }
        return $timestamp;
    }
    //
    // Converts track to label
    //
    function fn_track_to_label($track) {
        if ($track == 'Product')
            return 'Product';
        else {
            return $track;
        }
    }
    function fn_label_to_track($label) {
        if (trim($label) == 'Product')
            return 'Product';
        else {
            return $label;
        }
    }
    function fn_return_to_default($val) {
        if (trim($val) == '')
            return 'No';
        else {
            return $val;
        }
    }
    //
    // Export product taxes
    // Parameters:
    // @product_id - product ID
    // @lang_code - language code
    function fn_exim_get_taxes($product_taxes) {
        if ($product_taxes == 0) {
            return '';
        } else {
            $taxes = $this->ObjDatabase->readValue("SELECT taxClassName FROM " . DB_PREFIX . "tax_classes WHERE  taxClassID='" . $product_taxes . "'");
            return $this->fn_html_entity_decode($taxes['taxClassName']);
        }
    }
    function gettaxClassID($taxes) {
        if (empty($taxes)) {
            return '';
        } else {
            return $taxes = $this->ObjDatabase->getField("SELECT taxClassID
													  FROM
													  " . DB_PREFIX . "tax_classes WHERE
													  taxClassName='" . trim($taxes) . "'
													  AND taxClassStatus!='Deleted'");
        }
    }
    //
    // Import product taxes
    // Parameters:
    // @product_id - product ID
    // @data - comma delimited list of taxes
    // @lang_code - language code
    function fn_exim_set_taxes($product_id, $data, $lang_code = '') {
        if (empty($data)) {
            db_query("UPDATE ?:products SET tax_ids = '' WHERE product_id = ?i", $product_id);
            return true;
        }
        $tax_ids = db_get_fields("SELECT tax_id FROM ?:tax_descriptions WHERE tax IN (?a) AND lang_code = ?s", fn_explode(',', $data), $lang_code);
        $_data   = array(
            'tax_ids' => fn_create_set($tax_ids)
        );
        db_query('UPDATE ?:products SET ?u WHERE product_id = ?i', $_data, $product_id);
        return true;
    }
    //
    // Export product options
    // Parameters:
    // @product_id - product ID
    // @lang_code - language code
    function fn_exim_get_product_options($product_id, $lang_code = '') {
        $pair_delimiter = ':';
        $set_delimiter  = '; ';
        $vars_delimiter = ',';
        $result         = array();
        $options        = $this->fn_get_product_options($product_id, $lang_code);
        
        if (!empty($options)) {
            foreach ($options as $option_id => $o) {
                $str      = $this->fn_exim_post_item_id($option_id . (($o['isGlobal'] == 0) ? "" : "_L")) . "$o[option_name] $pair_delimiter $o[option_type]";
                $variants = array();
                if (!empty($o['variants'])) {
                    foreach ($o['variants'] as $variant_id => $v) {
                        $variants[] = $this->fn_exim_post_item_id($variant_id) . $v['variant_name'];
                    }
                    $str .= '[' . implode($vars_delimiter, $variants) . ']';
                }
                $result[$option_id] = $str;
                
            }
        }
       
        return !empty($result) ? $result : '';//implode($set_delimiter, $result)
    }
    function fn_exim_set_product_options($product_id, $data, $lang_code = '') {
        $pair_delimiter = ':';
        $set_delimiter  = ';';
        $vars_delimiter = ',';
        
        if (!empty($data)) {
            $options = $data;
            if (!empty($options)) {
                $updated_ids = array(); // store updated ids, delete other (if exist)
                $o_position  = 0;
                foreach ($options as $option) {
                    $option = trim($option);
                    
                    if (!empty($option)) {
                        $o_position += 10;
                        $pair     = explode($pair_delimiter, $option);
                        $variants = '';
                        if (is_array($pair)) {
                            array_walk($pair, array(
                                $this,
                                'fn_trim_helper'
                            ));
                            if (($pos = strpos($pair[1], '[')) !== false) { // option has variants
                                $variants = substr($pair[1], $pos + 1, strlen($pair[1]) - $pos - 2);
                                $variants = explode($vars_delimiter, $variants);
                            }
                            $option_str    = explode('_', $this->fn_exim_get_item_id($pair[0]));
                            $option_id     = $option_str[0];
                            $global_option = !empty($option_str[1]) && $option_str[1] == 'L';
                            $_restore      = false;
                            
                            if (!empty($option_id)) {
                                $_restores = $this->ObjDatabase->readValue("SELECT customOptionID FROM " . DB_PREFIX . "product_custom_option WHERE customOptionID =" . $option_id);
                                $_restore  = !$_restores['customOptionID'];
                            }
                            // Check if product option exists - FIXME!!! Global?					
                            if (empty($option_id)) {
                                $option_ids = $this->ObjDatabase->readValue("SELECT o.customOptionID FROM  " . DB_PREFIX . "product_custom_option_details as d INNER JOIN " . DB_PREFIX . "product_custom_option as o ON (o.customOptionID = d.customOptionID) LEFT JOIN " . DB_PREFIX . "product_custom_option_link ol ON(ol.customOptionID=o.customOptionID)
												    WHERE d.customOptionName ='" . $this->fn_html_entity_encode($pair[0]) . "' AND ol.productID='" . $product_id . "' AND 
												    d.languageID = " . $lang_code . " LIMIT 1");
                                $option_id  = $option_ids['customOptionID'];
                            }
                            $option_type = substr($pair[1], 0, 1);
                            // Generate array for variants
                            $v_data      = array();
                            $v_data_ids  = array();
                            if (!empty($variants) && is_array($variants)) {
                                $position = 0;
                                foreach ($variants as $v) {
                                    $position += 10;
                                    $v_data[] = array(
                                        'variant_name' => $v,
                                        'position' => $position
                                    );
                                    if ($variant_id = $this->fn_exim_get_item_id($v)) {
                                        $v_data_ids[] = array(
                                            'variant_id' => $variant_id,
                                            'variant_name' => $v,
                                            'position' => $position
                                        );
                                    } else {
                                        $v_data_ids[] = array(
                                            'variant_name' => $v,
                                            'position' => $position
                                        );
                                    }
                                }
                            }
                            /*if ($option_type == 'C') {
                            $v_data = $v_data_ids = array();
                            if (!empty($option_id)) { // check if variant exist
                            $v_data_ids = $this->ObjDatabase->readValues("SELECT * FROM ".DB_PREFIX."product_custom_option_variant WHERE customOptionID =".$option_id);
                            }
                            
                            // If not, generate default variant
                            if (empty($v_data_ids)) {
                            $v_data_ids = array(
                            array(
                            'position' => 1,
                            ),
                            );
                            }
                            }*/
                            $option_data               = array(
                                'option_name' => $pair[0],
                                'option_type' => $option_type,
                                'variants' => (empty($v_data_ids) ? $v_data : $v_data_ids)
                            );
                            $option_data['isGlobal']   = !empty($global_option) ? 1 : 0;
                            $option_data['product_id'] = $product_id;                           
                            // Option doesn't exist, create new
                            if (empty($option_id) || $_restore) {
                                if ($_restore) {
                                    $option_data['option_id'] = $option_id;
                                }
                                $option_data['position'] = $o_position;
                                $updated_ids[]           = $this->fn_update_product_option($option_data, 0, $lang_code);
                                // Option is exist, update it
                            } else {
                                $updated_ids[] = $this->fn_update_product_option($option_data, $option_id, $lang_code);
                            }
                        }
                    }
                    
                }
                 // Delete all other options
                if (!empty($updated_ids)) {
                    $obsolete_idstr = implode("','", $updated_ids);
                    $obsolete_ids   = $this->ObjDatabase->readValues("SELECT customOptionID FROM " . DB_PREFIX . "product_custom_option_link WHERE productID='" . $product_id . "' AND customOptionID NOT IN ('" . $obsolete_idstr . "')");
                    if (!empty($obsolete_ids)) {
                        foreach ($obsolete_ids as $o_id) {
                            $this->fn_delete_product_customoption($o_id['customOptionID'], $product_id);
                        }
                    }
                }
           }
        }
        if (empty($data)) {
            $obsolete_ids = $this->ObjDatabase->readValues("SELECT customOptionID FROM " . DB_PREFIX . "product_custom_option_link WHERE productID='" . $product_id . "'");
            if (!empty($obsolete_ids)) {
                foreach ($obsolete_ids as $o_id) {
                    $this->fn_delete_product_customoption($o_id['customOptionID'], $product_id);
                }
            }
        }
        return true;
    }
    //
    // Import product options
    // Parameters:
    // @product_id - product ID
    // @data - delimited list of product options and their values
    // @lang_code - language code
    function fn_exim_set_product_options_old($product_id, $data, $lang_code = '') {
        $pair_delimiter = ':';
        $set_delimiter  = ';';
        $vars_delimiter = ',';
        
        if (!empty($data)) {
            $options = explode($set_delimiter, $data);
            if (!empty($options)) {
                $updated_ids = array(); // store updated ids, delete other (if exist)
                $o_position  = 0;
                foreach ($options as $option) {
                    $option = trim($option);
                    if (!empty($option)) {
                        $o_position += 10;
                        $pair     = explode($pair_delimiter, $option);
                        $variants = '';
                        if (is_array($pair)) {
                            array_walk($pair, array(
                                $this,
                                'fn_trim_helper'
                            ));
                            if (($pos = strpos($pair[1], '[')) !== false) { // option has variants
                                $variants = substr($pair[1], $pos + 1, strlen($pair[1]) - $pos - 2);
                                $variants = explode($vars_delimiter, $variants);
                            }
                            $option_str    = explode('_', $this->fn_exim_get_item_id($pair[0]));
                            $option_id     = $option_str[0];
                            $global_option = !empty($option_str[1]) && $option_str[1] == 'L';
                            $_restore      = false;
                            if (!empty($option_id)) {
                                $_restores = $this->ObjDatabase->readValue("SELECT customOptionID FROM " . DB_PREFIX . "product_custom_option WHERE customOptionID =" . $option_id);
                                $_restore  = !$_restores['customOptionID'];
                            }
                            // Check if product option exists - FIXME!!! Global?					
                            if (empty($option_id)) {
                                $option_ids = $this->ObjDatabase->readValue("SELECT o.customOptionID FROM  " . DB_PREFIX . "product_custom_option_details as d INNER JOIN " . DB_PREFIX . "product_custom_option as o ON (o.customOptionID = d.customOptionID) LEFT JOIN " . DB_PREFIX . "product_custom_option_link ol ON(ol.customOptionID=o.customOptionID)
												    WHERE d.customOptionName ='" . $this->fn_html_entity_encode($pair[0]) . "' AND ol.productID='" . $product_id . "' AND 
												    d.languageID = " . $lang_code . " LIMIT 1");
                                $option_id  = $option_ids['customOptionID'];
                            }
                            $option_type = substr($pair[1], 0, 1);
                            // Generate array for variants
                            $v_data      = array();
                            $v_data_ids  = array();
                            if (!empty($variants) && is_array($variants)) {
                                $position = 0;
                                foreach ($variants as $v) {
                                    $position += 10;
                                    $v_data[] = array(
                                        'variant_name' => $v,
                                        'position' => $position
                                    );
                                    if ($variant_id = $this->fn_exim_get_item_id($v)) {
                                        $v_data_ids[] = array(
                                            'variant_id' => $variant_id,
                                            'variant_name' => $v,
                                            'position' => $position
                                        );
                                    } else {
                                        $v_data_ids[] = array(
                                            'variant_name' => $v,
                                            'position' => $position
                                        );
                                    }
                                }
                            }
                            /*if ($option_type == 'C') {
                            $v_data = $v_data_ids = array();
                            if (!empty($option_id)) { // check if variant exist
                            $v_data_ids = $this->ObjDatabase->readValues("SELECT * FROM ".DB_PREFIX."product_custom_option_variant WHERE customOptionID =".$option_id);
                            }
                            
                            // If not, generate default variant
                            if (empty($v_data_ids)) {
                            $v_data_ids = array(
                            array(
                            'position' => 1,
                            ),
                            );
                            }
                            }*/
                            $option_data               = array(
                                'option_name' => $pair[0],
                                'option_type' => $option_type,
                                'variants' => (empty($v_data_ids) ? $v_data : $v_data_ids)
                            );
                            $option_data['isGlobal']   = !empty($global_option) ? 1 : 0;
                            $option_data['product_id'] = $product_id;
                            // Option doesn't exist, create new
                            if (empty($option_id) || $_restore) {
                                if ($_restore) {
                                    $option_data['option_id'] = $option_id;
                                }
                                $option_data['position'] = $o_position;
                                $updated_ids[]           = $this->fn_update_product_option($option_data, 0, $lang_code);
                                // Option is exist, update it
                            } else {
                                $updated_ids[] = $this->fn_update_product_option($option_data, $option_id, $lang_code);
                            }
                        }
                    }
                }
                // Delete all other options
                if (!empty($updated_ids)) {
                    $obsolete_idstr = implode("','", $updated_ids);
                    $obsolete_ids   = $this->ObjDatabase->readValues("SELECT customOptionID FROM " . DB_PREFIX . "product_custom_option_link WHERE productID='" . $product_id . "' AND customOptionID NOT IN ('" . $obsolete_idstr . "')");
                    if (!empty($obsolete_ids)) {
                        foreach ($obsolete_ids as $o_id) {
                            $this->fn_delete_product_customoption($o_id['customOptionID'], $product_id);
                        }
                    }
                }
            }
        }
        if (empty($data)) {
            $obsolete_ids = $this->ObjDatabase->readValues("SELECT customOptionID FROM " . DB_PREFIX . "product_custom_option_link WHERE productID='" . $product_id . "'");
            if (!empty($obsolete_ids)) {
                foreach ($obsolete_ids as $o_id) {
                    $this->fn_delete_product_customoption($o_id['customOptionID'], $product_id);
                }
            }
        }
        return true;
    }
    /**
     * Deletes options and their variants by option identifier
     *
     * @param int $option_id Option identifier
     * @param int $pid Identifier of the product from which the option should be removed (for global options)
     * @return bool True on success, false otherwise
     */
    function fn_delete_product_customoption($option_id, $pid = 0) {
        if (!empty($option_id)) {
            /**
             * Adds additional actions before product option deleting
             *
             * @param int $option_id Option identifier
             * @param int $pid Product identifier
             */
            $is_global = $this->ObjDatabase->readValue("SELECT isGlobal FROM " . DB_PREFIX . "product_custom_option WHERE  customOptionID =" . $option_id);
            $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_custom_option_link WHERE productID =" . $pid . " AND customOptionID = " . $option_id);
            if ($is_global == 0) {
                // Product option
                $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_custom_option_details WHERE  customOptionID =" . $option_id);
                $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_custom_option WHERE  customOptionID = " . $option_id);
                //fn_delete_product_option_variants($option_id);
            }
            return true;
        }
        return false;
    }
    //
    // Inserts ID of element to the csv file
    // @item_id - id of an item
    //
    function fn_exim_post_item_id($item_id) {
        return '{' . $item_id . '}';
    }
    //
    // Gets element ID and updates the element name
    // @element - element
    //
    function fn_exim_get_item_id(&$element) {
        $item_id = '';
        if ($item_id = substr($element, 0, strpos($element, '}'))) {
            $element = substr($element, strpos($element, '}') + 1);
            $item_id = substr($item_id, 1);
        }
        return $item_id;
    }
    function fn_exim_get_item_name(&$element) {
        /*$item_id = '';
        if ($item_id = substr($element, 0, strpos($element, ')'))) {
        $element = substr($element, strpos($element, ')') + 1);
        $item_id = substr($item_id, 1);
        }*/
        return trim($element, '()');
    }
    function fn_array_key_intersect(&$a, &$b) {
        $array = array();
        while (list($key, $value) = each($a)) {
            if (isset($b[$key])) {
                $array[$key] = $value;
            }
        }
        return $array;
    }
    /**
     * Get the EDP downloaded
     *
     * @param string $path path to the file
     * @param string $filename file name to be displayed in download dialog
     * @return bool Always false
     */
    function fn_get_file($filepath, $filename = '') {
        
        $fd = @fopen($filepath, 'rb');
        if ($fd) {
            $fsize = filesize($filepath);
            $ftime = date('D, d M Y H:i:s T', filemtime($filepath)); // get last modified time
            if (isset($_SERVER['HTTP_RANGE'])) {
                header($_SERVER['SERVER_PROTOCOL'] . ' 206 Partial Content');
                $range = $_SERVER['HTTP_RANGE'];
                $range = str_replace('bytes=', '', $range);
                list($range, $end) = explode('-', $range);
                if (!empty($range)) {
                    fseek($fd, $range);
                }
            } else {
                header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK');
                $range = 0;
            }
            // Browser bug workaround: Filenames can't be sent to IE if there is any kind of traffic compression enabled on the server side
            if ('USER_AGENT' == 'ie') {
                if (function_exists('apache_setenv')) {
                    apache_setenv('no-gzip', '1');
                }
                ini_set("zlib.output_compression", "Off");
                // Browser bug workaround: During the file download with IE, non-ASCII filenames appears with a broken encoding
                $filename = rawurlencode($filename);
            }
                       
            header('Content-Encoding: UTF-8');             
            header('Content-Type: text/csv;charset=UTF-8');
            header("Content-Disposition: attachment; filename=\"$filename\"");           
            header('Last-Modified: ' . $ftime);
            header('Accept-Ranges: bytes');
            header('Content-Length: ' . ($fsize - $range));
            header('Pragma: public');
            header('Expires: 0');
            header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
            header('Cache-Control: private', false);            
            if ($range) {
                header("Content-Range: bytes $range-" . ($fsize - 1) . '/' . $fsize);
            }
            
            $result = fpassthru($fd);   
            
            if ($result == false) {
                fclose($fd);
                return false;
            } else {
                fclose($fd);
                exit;
            }
        }
        return false;
    }
    function fn_get_product_options($product_id, $lang_code) {
        $ObjCustom                         = new CustomOptionModel();
        $condition                         = $_status = $join = '';
        $extra_variant_fields              = '';
        $option_ids                        = $variants_ids = $options = array();
        $selectable_option_types           = array(
            'S',
            'R',
            'C'
        );
        $inputKeys                         = $ObjCustom->getInputShortKeys();
        $customAttributeArray['productID'] = $product_id;
        $languageIDs['Current']            = $lang_code;
        $resoptions                        = $ObjCustom->listCustomProductOption($languageIDs, $customAttributeArray);
        foreach ($resoptions as $key => $_options) {
            $options[$_options['customOptionID']]['option_name'] = $this->fn_html_entity_decode($_options['customOptionName']);
            $options[$_options['customOptionID']]['option_type'] = $inputKeys[$_options['inputType']];
            $options[$_options['customOptionID']]['isGlobal']    = $_options['isGlobal'];
            if ($_options['inputType'] == 'multiselect' || $_options['inputType'] == 'select')
                $option_ids[] = $_options['customOptionID'];
        }
        if (!empty($option_ids)) {
            $resVariants = $ObjCustom->getVariantsForOptions($option_ids, $languageIDs);
            if (count($resVariants) > 0) {
                foreach ($resVariants as $key => $_variants) {
                    $variants[$_variants['customOptionID']][$_variants['customOptionVariantID']]['variant_name'] = $this->fn_html_entity_decode($_variants['value']);
                }
            }
            foreach ($options as $key => $dataoptions) {
                $options[$key]['variants'] = !empty($variants[$key]) ? $variants[$key] : array();
            }
        }
        return $options;
    }
    function fn_exim_get_product_attributes($product_id, $lang_code = '',$setID='') {
        
        $ObjAttribute                     = new AttributeModel();
        $ObjProduct                       = new ProductModel();
        $ObjCustom                        = new CustomOptionModel();
        $inputKeys                        = $ObjCustom->getInputShortKeys();
        $attrParamArray['attributeSetID'] = $ObjProduct->getAttrSetID($product_id);
        $attrParamArray['productID']      = $product_id;
        $attrParamArray['attrStatus']     = 'A';
        $attrParamArray['mode']           = 'attributeDetails';
        $languageIDs['Current']           = $lang_code;
        $attributesGroupWise              = $ObjAttribute->listAttributesGroupWise($languageIDs, $attrParamArray);
        $pair_delimiter                   = ':';
        $set_delimiter                    = '; ';
        $attributeArray                   = array();
        $result                           = array();
        if (isset($attributesGroupWise)) {
            $attrIdArray = array();
            foreach ($attributesGroupWise as $attributes) {
                if (in_array($attributes['attributeID'], $attrIdArray))
                    $features_delimiter = ", ";
                else
                    $features_delimiter = "";
                if (empty($attributeArray['attributes'][$attributes['attributeID']]['attrValue']))
                    $attributeArray['attributes'][$attributes['attributeID']]['attrValue'] = '';
                $attrIdArray[$attributes['attributeID']]                                   = $attributes['attributeID'];
                $attributeArray['attributes'][$attributes['attributeID']]['GroupName']     = $attributes['name'];
                $attributeArray['attributes'][$attributes['attributeID']]['attrInputType'] = $attributes['attrInputType'];
                $attributeArray['attributes'][$attributes['attributeID']]['attrName']      = $attributes['attrName'];
                $attributeArray['attributes'][$attributes['attributeID']]['attrValue']     = $attributeArray['attributes'][$attributes['attributeID']]['attrValue'] .(($attributes['attributeValue']!='')?($features_delimiter . $attributes['attributeValue']):'');
                $attributeArray['attributes'][$attributes['attributeID']]['attrValueID']   = $attributes['attrValueID'];
            }
        }
        //echo "<pre>";print_r($attributeArray);exit;
        if (!empty($attributeArray)) {
            foreach ($attributeArray as $parent_id => $attributes) {
                $parent = '';
                foreach ($attributes as $attribute_id => $f) {
                    if (!empty($attribute_id)) {
                        $parent = '(' . $this->fn_html_entity_decode($f['GroupName']) . ') ';
                    }
                    if ($f['attrInputType'] != 'file') {
                        $f['attrName'] = $this->fn_html_entity_decode($f['attrName']);
                        
                        $result[$attribute_id]      = $this->fn_exim_post_item_id($attribute_id) . $parent . "{$f['attrName']}{$pair_delimiter} {$inputKeys[$f['attrInputType']]}[" . $f['attrValue'] . ']';
                    }
                }
            }
            
        }
        //echo "<pre>";print_r($result);exit;
        return !empty($result) ?  $result: '';//implode($set_delimiter, $result)
    }
    // Import product features
    // Parameters:
    // @product_id - product ID
    // @data - delimited list of product features and their values
    // @lang_code - language code
    /*
    value C (checkbox)
    value T (text)
    
    variant_id M (multi)
    variant_id S (select)
    variant_id N (select number)
    variant_id E (select extended)
    
    value_int O (number)
    value_int D (date)
    
    */
    function fn_exim_set_product_attributes($product_id, $setID, $data, $lang_code = '1') {
        $ObjLanguage        = new LanguageModel();
        $ObjCustom          = new CustomOptionModel();
        $inputKeys          = $ObjCustom->getInputShortKeys();
        $resLanguages       = $ObjLanguage->listLanguages('', 'Active');
        $pair_delimiter     = ':';
        $set_delimiter      = ';';
        $features_delimiter = ',';

        if (!empty($data)) {
           
            $set_delimiter                    = '; ';
            $tempdata = $data;
            $data = '';
            foreach($tempdata as $t=>$tmp) {
                if($tmp=='') {
                    $resFeatureType = $this->ObjDatabase->readValue("SELECT attrInputType FROM " . DB_PREFIX . "attributes WHERE attributeKey ='" . $t . "'");
                    if(!empty($resFeatureType['attrInputType']))
                    {
                        if(strtoupper($resFeatureType['attrInputType'][0]) == 'M')
                                $resFeatureType['attrInputType'][0] = 'C';
                        $tmp = strtoupper($resFeatureType['attrInputType'][0]).'[]';//'I[]'
                    }
                    else
                        $tmp = 'I[]';

                }                
                $data = (!empty($data))?$data.' '.$t.':'.$tmp.';':$t.':'.$tmp.';';
            } 

            if (preg_match_all("/[ ]*(\{\d+\})?[ ]*(\(.+?\))?[ ]*(.+?):[ ]*([\w]{1})[ ]*\[(.*?)\];?/", $data, $features)) {
                //print_r($features[3]);exit;

                foreach ($features[3] as $k => $feature) {
                    // feature data
                    $feature_id_csv = $feature;//$this->fn_exim_get_item_id($features[1][$k]);
                    $feature_type   = $features[4][$k];
                    $vars           = explode($features_delimiter, $features[5][$k]);
                    // find group_id
                    $group_id       = 0;
                    $group_exists   = true;
                    if (!empty($features[2][$k])) {
                        $group_id = $this->fn_exim_check_attribute_group($features[2][$k], $lang_code, $setID, $group_exists);
                    }
                    // try to find similar feature (same description, type, parent)
                    $feature_ids = $this->ObjDatabase->readValue("SELECT attributeID FROM " . DB_PREFIX . "attributes WHERE attrStatus='A' AND attributeKey ='" . $feature_id_csv . "'");
                    $feature_id  = $feature_ids['attributeID'];

                    if (empty($feature_id) && empty($feature_id_csv)) {
                        $condition   = "WHERE attrName ='" . $this->fn_html_entity_encode($feature) . "' AND  languageID ='" . $lang_code . "'";
                        $feature_ids = $this->ObjDatabase->readValue("SELECT " . DB_PREFIX . "attributes.attributeID FROM " . DB_PREFIX . "attribute_details
							LEFT JOIN " . DB_PREFIX . "attributes ON " . DB_PREFIX . "attributes.attributeID = " . DB_PREFIX . "attribute_details.attributeID " . $condition);
                        $feature_id  = $feature_ids['attributeID'];
                    }
                    if (empty($feature_id)) {
                        $attrcode                  = $feature . "-" . rand(700, 6544);
                        // insert new feature
                        $feature_data              = array(
                            'attrInputType' => array_search($feature_type, $inputKeys),
                            'attrStatus' => 'A',
                            'attributeKey' => $attrcode
                        );
                        $feature_datas['attrName'] = $feature;
                        $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "attributes" . $this->insert($feature_data));
                        $feature_id = $feature_datas['attributeID'] = $this->ObjDatabase->getInsertId();
                        foreach ($resLanguages as $key => $_v) {
                            $feature_datas['languageID'] = $_v['languageID'];
                            $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "attribute_details" . $this->insert($feature_datas));
                        }
                    } else {
                       // $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "attribute_details (attributeID, attrName, languageID) VALUES ('" . $feature_id . "','" . $this->fn_html_entity_encode($feature) . "','" . $lang_code . "')");
                    }
                    $group_data = array(
                        'attributeGroupID' => $group_id,
                        'attributeID' => $feature_id,
                        'sortOrder' => '1'
                    );
                    if($group_id>0) {
                    $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "attribute_to_group" . $this->insert($group_data));
                    }
                    // import feature variants
                    $i_data = array(
                        'productID' => $product_id,
                        'attributeID' => $feature_id
                    );
                    if (strpos('CS', $feature_type) !== false) { // variant IDs
                        $variantIDs       = array();
                        $existent_variant = array();
                        array_walk($vars, array(
                            $this,
                            'fn_trim_helper'
                        ));
//                        array_walk($vars, array(
//                            $this,

//                            'fn_html_entity_encode'
//                        ));
//                        array_walk($vars, array(
//                            $this,
//                            'fn_htmlspecialchars_wquotes'
//                        ));
                        $vars = array_map('htmlspecialchars',$vars);
                        $vars = array_map('addslashes',$vars);

                        $varstring         = implode("','",$vars);
                        $existent_variants = $this->ObjDatabase->readValues("SELECT pfvd.attrOptionID, attrOptName FROM " . DB_PREFIX . "attribute_option_details AS pfvd " . "LEFT JOIN " . DB_PREFIX . "attribute_options AS pfv ON pfv.attrOptionID = pfvd.attrOptionID " . "WHERE attributeID = " . $feature_id . "  AND attrOptName IN ('" . $varstring . "') AND languageID = " . $lang_code);
                        if ($existent_variants) {
                            foreach ($existent_variants as $v) {
                                $existent_variant[$v['attrOptionID']] = $v['attrOptName'];
                            }
                        }
                        foreach ($vars as $v) {
                            if(trim($v)=='')
                                continue;
                            if ($feature_type == 'N') {
                                $i_data['value_int'] = $v;
                            }


                            if (in_array(stripslashes($v), $existent_variant)) { // variant exists							
                                $variantIDs[] = $i_data['attrOptionID'] = array_search(stripslashes($v), $existent_variant);
                                //echo "REPLACE INTO ".DB_PREFIX."product_attribute_values".$this->insert($i_data);
                                $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "product_attribute_values" . $this->insert($i_data));
                            } else { // add variant
                                $v_data = array(
                                    'attributeID' => $feature_id
                                );
                                //echo "INSERT INTO ".DB_PREFIX."attribute_options".$this->insert($v_data);
                                $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "attribute_options" . $this->insert($v_data));
                                $variantIDs[] = $variant_id = $this->ObjDatabase->getInsertId();
                                $v_data       = array(
                                    'attrOptionID' => $variant_id,
                                    'attrOptName' => html_entity_decode($v)

                                );
                                foreach ($resLanguages as $key => $_v) {
                                    $v_data['languageID'] = $_v['languageID'];
                                    $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "attribute_option_details" . $this->insert($v_data));
                                }
                                $i_data['attrOptionID'] = $variant_id;
                                $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "product_attribute_values" . $this->insert($i_data));
                            }
                        }
                        if(!empty(array_filter($variantIDs)) && count(array_filter($variantIDs))>0)
                            $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_attribute_values WHERE attrOptionID NOT IN(" . implode(",", $variantIDs) . ") AND productID='" . $product_id . "' AND  attributeID=" . $feature_id);
                    } elseif (strpos('DTFW', $feature_type) !== false) {
                        $i_datas['languageID']   = $lang_code; // value INT
                        //$i_data['attrDetValue'] = ($feature_type == 'D' && strpos($vars[0], '/') !== false) ? $this->fn_parse_date($vars[0]) : $vars[0];
                        $i_datas['attrDetValue'] = ($feature_type == 'D' && strpos($vars[0], '/') !== false) ? $vars[0] : $vars[0];
                        //$this->ObjDatabase->setQuery("REPLACE INTO ".DB_PREFIX."product_attribute_values".$this->insert($i_data));
                        $is_exists               = $this->ObjDatabase->readValue("SELECT attrValueID FROM " . DB_PREFIX . "product_attribute_values DV  WHERE DV.attrOptionID=0 AND DV.productID=" . $product_id . "  AND
											   DV.attributeID ='" . $i_data['attributeID'] . "'");
                        if ($is_exists['attrValueID']) {
                            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_attribute_value_details SET attrDetValue='" . $i_datas['attrDetValue'] . "' WHERE attrValueID=" . $is_exists['attrValueID'] . "  AND languageID =" . $i_datas['languageID']);
                        } else {
                            $in_data['productID']    = $i_data['productID'];
                            $in_data['attributeID']  = $i_data['attributeID'];
                            $in_data['attrOptionID'] = 0;
                            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_attribute_values" . $this->insert($in_data));
                            $i_datas['attrValueID'] = $this->ObjDatabase->getInsertId();
                            foreach ($resLanguages as $key => $_v) {
                                $i_datas['languageID'] = $_v['languageID'];
                            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_attribute_value_details" . $this->insert($i_datas));
                        }

                        }
                    } else { // TEXT
                        $i_datas                 = array();
                        $i_datas['attrDetValue'] = $this->fn_html_entity_encode($vars[0]);
                        $i_datas['languageID']   = $lang_code;
                        $is_exists               = $this->ObjDatabase->readValue("SELECT DV.attrValueID as attrValueID , DVD.attrValDetID  FROM " . DB_PREFIX . "product_attribute_values DV  "
                                . " LEFT JOIN " . DB_PREFIX . "product_attribute_value_details DVD ON DV.attrValueID=DVD.attrValueID AND languageID ='" . $i_datas['languageID'] . "'
                                    WHERE DV.attrOptionID=0 AND DV.productID=" . $product_id . "  AND
						
						
											   DV.attributeID ='" . $i_data['attributeID'] . "'");
                        if ($is_exists['attrValueID']) {
                            if ($is_exists['attrValDetID']){
                                $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_attribute_value_details SET attrDetValue='" . $i_datas['attrDetValue'] . "' WHERE attrValueID='" . $is_exists['attrValueID'] . "'  AND languageID ='" . $i_datas['languageID'] . "'");
                            } else {
                                $i_datas['attrValueID'] = $is_exists['attrValueID'];
                                foreach ($resLanguages as $key => $_v) {
                                    $i_datas['languageID'] = $_v['languageID'];
                                    $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_attribute_value_details" . $this->insert($i_datas));
                                } 
                            }
                        } else {
                            $int_data['productID']    = $i_data['productID'];
                            $int_data['attributeID']  = $i_data['attributeID'];
                            $int_data['attrOptionID'] = 0;
                            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_attribute_values" . $this->insert($int_data));
                            $i_datas['attrValueID'] = $this->ObjDatabase->getInsertId();
                            foreach ($resLanguages as $key => $_v) {
                                $i_datas['languageID'] = $_v['languageID'];
                            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_attribute_value_details" . $this->insert($i_datas));

                        }
                    }
                }
            }
        }

        }
        return true;
    }
  
    /**
     * If feature group exists return it id, else create such groups for all available langs
     *
     * @param string $group group name
     * @param string $lang_code
     * @param boolean $group_exists true if group already exists, false otherwise.
     * 
     * @return integer ID of group 
     */
    function fn_exim_check_attribute_group($group, $lang_code, $setID, &$group_exists) {
        $ObjLanguage  = new LanguageModel();
        $resLanguages = $ObjLanguage->listLanguages("", "Active");
        $group        = trim($group, '()');
        $group_ids    = $this->ObjDatabase->readValue("SELECT  attrGroupDet.attributeGroupID FROM " . DB_PREFIX . "attribute_group_details attrGroupDet LEFT JOIN " . DB_PREFIX . "attribute_group attrGroup ON(attrGroupDet.attributeGroupID=attrGroup.attributeGroupID) WHERE attributeSetID='" . $setID . "' AND name ='" . $group . "' AND languageID = " . $lang_code . " LIMIT 1");
        $group_id     = $group_ids['attributeGroupID'];
        if (empty($group_id)) {
            // Create new feature
            $group_data = array(
                'attributeSetID' => $setID,
                'sortOrder' => '999'
            );
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "attribute_group" . $this->insert($group_data));
            $group_id   = $this->ObjDatabase->getInsertId();
            $group_data = array(
                'attributeGroupID' => $group_id,
                'name' => $group
            );
            foreach ($resLanguages as $key => $_v) {
                $group_data['languageID'] = $_v['languageID'];
                $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "attribute_group_details" . $this->insert($group_data));
            }
            $group_exists = false;
        } else {
            $group_exists = true;
        }
        return $group_id;
    }
    function fn_exim_get_product_variants($productID, $lang_code) {
        $pair_delimiter         = ':';
        $var_delimiter          = '/';
        $set_delimiter          = ';';
        $languageIDs['Current'] = $lang_code;
        $result                 = array();
        $ObjProduct             = new ProductModel();
        $resProductOptions      = $ObjProduct->listProductOptions($languageIDs, $productID, "Active", "No", 'list');
        $parent                 = '';
        foreach ($resProductOptions as $o) {
            $parent   = '(' . $this->fn_html_entity_decode($o['productOptionName']) . ') ';
            $result[] = $this->fn_exim_post_item_id($o['productOptionID']) . $parent . "{$pair_delimiter} {$o['optionSKU']}[P(" . $o['productOptionRegularPrice'] . $var_delimiter . $o['productOptionProductPrice'] . '),B(' . $o['packageLength'] . $var_delimiter . $o['packageWidth'] . $var_delimiter . $o['packageHeight'] . $var_delimiter . $o['packageWeight'] . '),C(' . $o['optionBarCode'] . '),Q(' . $o['productOptionQuantity'] . ')]';
        }
        return !empty($result) ? implode($set_delimiter, $result) : '';
    }
    function fn_exim_set_product_variants($product_id, $data, $avail_multiple, $lang_code = '',$businessID='') {
        $pair_delimiter = ':';
        $set_delimiter  = ';';
        $vars_delimiter = ',';
        $val_delimiter  = '/';
        $avail_multiple = trim($avail_multiple);
        //print_r($data);
        //echo $avail_multiple;exit;
        if ((!empty($data)) && ($avail_multiple == 'Yes')) {
            $options = explode($set_delimiter, $data);
            //print_r($options);exit;
            if (!empty($options)) {
                $updated_ids = array(); // store updated ids, delete other (if exist)
                $o_position  = 0;
                foreach ($options as $option) {
                    if (!empty($option)) {
                        $o_position += 10;
                        $pair     = explode($pair_delimiter, $option);
                        $variants = '';
                        if (is_array($pair)) {
                            array_walk($pair, array(
                                $this,
                                'fn_trim_helper'
                            ));
                            if (($pos = strpos($pair[1], '[')) !== false) { // option has variants
                                $variants = substr($pair[1], $pos + 1, strlen($pair[1]) - $pos - 2);
                                $variants = explode($vars_delimiter, $variants);
                            }
                            //$option_str = $this->fn_exim_get_item_id($pair[0]);
                            $option_id   = $this->fn_exim_get_item_id($pair[0]);
                            $option_name = $this->fn_exim_get_item_name($pair[0]);
                            $_restore    = false;
                            if (!empty($option_id)) {
                                $result = $this->ObjDatabase->readValue("SELECT productOptionID FROM " . DB_PREFIX . "product_options WHERE productOptionID ='" . $option_id . "'");
                                if ($result['productOptionID'])
                                    $_restore = true;
                            }
                            // Check if product option exists - FIXME!!! Global?
                            if (empty($option_id)) {
                                $sql        = "
								SELECT 
									productOpt.productOptionID 
								FROM 
										" . DB_PREFIX . "product_option_details AS productOptDet 
									INNER JOIN 
										" . DB_PREFIX . "product_options AS productOpt 
											ON 	(
												productOpt.productOptionID = productOptDet.productOptionID 
												AND 
												productOpt.productID ='" . $product_id . "' 
											)
								WHERE 
									productOptDet.productOptionName ='" . $this->fn_html_entity_encode($option_name) . "' 
									AND 
									productOptDet.languageID ='" . $lang_code . "' 
								LIMIT 
									1";
                                $option_ids = $this->ObjDatabase->readValue($sql);
                                $option_id  = $option_ids['productOptionID'];
                            }
                            $option_skuStr = explode('[', $pair[1]);
                            $option_sku    = $option_skuStr[0];
                            if (empty($option_id)) {
                                $sqlOpt                                     = "SELECT opt.productOptionID FROM " . DB_PREFIX . "product_options opt Join " . DB_PREFIX . "products product ON (opt.productID=product.productID) WHERE  opt.optionSKU='" . $optionSku . "'";
                                if($businessID!='') {
                                    $sqlOpt                                 .= " AND product.businessID='".$businessID."'";
                                }
                                $option_id = $this->ObjDatabase->getField($sqlOpt);
                            }
                            // Generate array for variants
                            $v_data     = array();
                            $v_data_ids = array();
                            
                            if (!empty($variants) && is_array($variants)) {
                                $position = 0;
                                foreach ($variants as $v) {
                                    $position += 10;
                                    $v_data[] = array(
                                        'variant_name' => $v,
                                        'position' => $position
                                    );
                                }
                            }
                            $option_data = array(
                                'option_name' => $option_name,
                                'option_sku' => $option_sku,
                                'variants' => $v_data
                            );
                            // Option doesn't exist, create new					
                            if (empty($option_id)) {
                                $option_data['product_id'] = $product_id;
                                $updated_ids[]             = $this->fn_update_product_variant($option_data, 0, $lang_code);
                                // Option is exist, update it
                            } else {
                                $option_data['product_id'] = $product_id;
                                $updated_ids[]             = $this->fn_update_product_variant($option_data, $option_id, $lang_code);
                            }
                        }
                    }
                }
                // Delete all other options
                if (!empty($updated_ids)) {
                    $updated_ids  = implode(',', $updated_ids);
                    $sql          = "
						SELECT  
							productOptionID 
						FROM 
							" . DB_PREFIX . "product_options 
						WHERE 
							productOptionDefault!='Yes' 
							AND 
							productOptionID NOT IN (" . $updated_ids . ") 
							AND 
							productID =" . $product_id;
                    $obsolete_ids = $this->ObjDatabase->readValues($sql);
                    if (!empty($obsolete_ids)) {
                        foreach ($obsolete_ids as $o_id) {
                            $this->fn_delete_product_option($o_id['productOptionID'], $product_id);
                        }
                    }
                }
            }
        } elseif (($avail_multiple != 'Yes')) {
            $sql          = "
			SELECT  
				productOptionID 
			FROM 
				" . DB_PREFIX . "product_options 
			WHERE 
				productOptionDefault!='Yes' 
			AND 
				productID =" . $product_id;
            $obsolete_ids = $this->ObjDatabase->readValues($sql);
            if (!empty($obsolete_ids)) {
                foreach ($obsolete_ids as $o_id) {
                    $this->fn_delete_product_option($o_id['productOptionID'], $product_id);
                }
            }
        }
        return true;
    }
    // Import product options
    // Parameters:
    // @product_id - product ID
    // @data - delimited list of product options and their values
    // @lang_code - language code
    function fn_html_entity_decode($data) {
        return html_entity_decode($data);
    }
    function fn_exim_get_product_combination($combination, $lang_code) {
        $return                 = array();
        $ObjCustom              = new CustomOptionModel();
        $languageIDs['Current'] = $lang_code;
        $comboArray             = $ObjCustom->getCombinationVariants($languageIDs, $combination);
        if (count($comboArray) > 0) {
            foreach ($comboArray as $combostr) {
                $return[] = $this->fn_html_entity_decode($combostr['customOptionName']) . ":" . $combostr['variantName'];
            }
        }
        return !empty($return) ? implode(', ', $return) : '';
    }
    function fn_export_thumb($image_id, $object, $backup_path = '') {
        return "";
    }
    function fn_exim_get_object_sku($objectID, $objectType) {
        if ($objectType == 'DO') {
            $sql = "SELECT optionSKU as SKU FROM " . DB_PREFIX . "product_options WHERE productOptionID ='" . $objectID . "'";
        } else {
            $sql = "SELECT combinationSKU as SKU FROM " . DB_PREFIX . "product_combination WHERE combinationID ='" . $objectID . "'";
        }
        $sku = $this->ObjDatabase->readValue($sql);
        if (!empty($sku)) {
            return $this->fn_html_entity_decode($sku['SKU']);
        } else
            return "";
    }
    function fn_exim_get_product_name($productID, $langauageID) {
        $ObjProduct = new ProductModel();
        $name       = $ObjProduct->getProductNameByProductID($productID, $langauageID);
        return $this->fn_html_entity_decode($name);
    }
    // --------- ExIm core functions ------------------
    //
    // Import data using pattern
    // Parameters:
    // @pattern - import/export pattern
    // @import_data - data to import
    // @options - import options
    public function import($patternID, $pre_process = '') {
        $this->fn_remove_exim_data();
        $file = $this->fn_filter_uploaded_data('csv_file');
        if (!empty($file)) {
            //$pattern = fn_get_pattern_definition($_REQUEST['pattern_id'], 'import');
            if ($patternID == 'products') {     
                $pattern = $this->getProductSchema('', $pre_process, $pre_process['businessID'],'','',$pre_process['languageID']);                
            }
            elseif ($patternID == 'product_combinations')
                $pattern = $this->getCombinationSchema('', $pre_process['businessID'],$pre_process['languageID']);
            elseif ($patternID == 'product_images')
                $pattern = $this->getImagesSchema('', $pre_process['businessID'],$pre_process['languageID']);
            elseif ($patternID == 'product_attributes')
                $pattern = $this->getAttributesSchema('', $pre_process['businessID'],$pre_process['languageID']);
            elseif ($patternID == 'product_custom_options')
                $pattern = $this->getCustomOptionsSchema('', $pre_process['businessID'],$pre_process['languageID']);
            elseif ($patternID == 'brands')
                $pattern = $this->getBrandSchema($pre_process['languageID']);
            $this->lang_xml = $pre_process['languageXml'];
            //echo "<pre>";print_r($_REQUEST['import_options']);exit;
            
            if (($data = $this->fn_get_csv($pattern, $file[0]['path'], $_REQUEST['import_options'])) != false) {
                
                $status1 = $this->fn_import($pattern, $data, $_REQUEST['import_options'],array(),$patternID);
                if ($status1) { 
                    $import_log['Status']    = "imported";
                    $import_log['Success']   = $this->import_status['Status'];
                    $import_log['Skipped']   = (!empty($this->import_status['Skipped'])) ? $this->import_status['Skipped'] : '';
                    $import_log['count_log'] = $this->import_status['count_log'];
                    if ($patternID == 'product_images') {
                        $import_log['count_log']['new']   = $this->import_db_skip_new;
                        $import_log['count_log']['exist'] = $this->import_db_skip_exist;
                        $import_log['count_log']['total'] = $this->import_db_skip_new + $this->import_db_skip_exist + $this->import_status['count_log']['skipped'];
                    }
                } else {
                    $import_log['Status'] = "import_fail";
                }
            } else {
                
                $import_log['Status'] = "import_fail";
            }
            $import_log['Error'] = $this->import_error;
        } else {
            $import_log['Status'] = "no_file";
        }
        return $import_log;
    }
    /**
     * Rebuilds $_FILES array to more user-friendly look
     *
     * @param string $name Name of file parameter
     * @return array Rebuilt file array
     */
    function fn_rebuild_files($name) {
        $rebuilt = array();
        if (!is_array(@$_FILES[$name])) {
            return $rebuilt;
        }
        if (isset($_FILES[$name]['error'])) {
            if (!is_array($_FILES[$name]['error'])) {
                return $_FILES[$name];
            }
        } elseif ($this->fn_is_empty($_FILES[$name]['size'])) {
            return $_FILES[$name];
        }
        foreach ($_FILES[$name] as $k => $v) {
            if ($k == 'tmp_name') {
                $k = 'path';
            }
            $rebuilt = $this->fn_array_multimerge($rebuilt, $v, $k);
        }
        return $rebuilt;
    }
    function fn_array_multimerge($array1, $array2, $name) {
        if (is_array($array2) && count($array2)) {
            foreach ($array2 as $k => $v) {
                if (is_array($v) && count($v)) {
                    $array1[$k] = $this->fn_array_multimerge(@$array1[$k], $v, $name);
                } else {
                    $array1[$k][$name] = ($name == 'error') ? 0 : $v;
                }
            }
        } else {
            $array1 = $array2;
        }
        return $array1;
    }
    //
    // Advanced checking for variable emptyness
    //
    function fn_is_empty($var) {
        if (!is_array($var)) {
            return (empty($var));
        } else {
            foreach ($var as $k => $v) {
                if (empty($v)) {
                    unset($var[$k]);
                    continue;
                }
                if (is_array($v) && $this->fn_is_empty($v)) {
                    unset($var[$k]);
                }
            }
            return (empty($var)) ? true : false;
        }
    }
    /**
     * Function get local uploaded
     *
     * @param unknown_type $val
     * @staticvar array $cache
     * @return unknown
     */
    function fn_get_local_data($val) {
        $cache    = array();
        $tempfile = $this->fn_create_temp_file();
        if (move_uploaded_file($val['path'], $tempfile) == true) {
            @chmod($tempfile, 0666);
            $cache[$val['path']] = $tempfile;
        }
        $val['path'] = (isset($cache[$val['path']])) ? $cache[$val['path']] : '';
        return $val;
    }
    /**
     * Create temporary file
     *
     * @return temporary file
     */
    function fn_create_temp_file() {
        if (!file_exists(__DIR_EXIM . 'tmp'))
            mkdir(__DIR_EXIM . 'tmp');
        return tempnam(__DIR_EXIM . 'tmp/', 'tmp_');
    }
    function fn_filter_uploaded_data($name) {
        $udata_local = $this->fn_rebuild_files('file_' . $name);
        $udata_other = !empty($_REQUEST['file_' . $name]) ? $_REQUEST['file_' . $name] : array();
        $filtered    = array();
        //if ($type == 'local' && !fn_is_empty(@$udata_local[$id])) 0
        $this->fn_remove_temp_data();
        $filtered[0] = $this->fn_get_local_data($udata_local[0]);
        if (empty($udata_local[0]['size'])) {
            //fn_set_notification('E', fn_get_lang_var('error'), fn_get_lang_var('cant_upload_file'));
            unset($filtered[0]);
        }
        //} 
        /*if (!empty($filtered[$id]['name'])) {
        $filtered[$id]['name'] = str_replace(' ', '_', urldecode($filtered[$id]['name'])); // replace spaces with underscores
        $ext = fn_get_file_ext($filtered[$id]['name']);
        if (in_array(fn_strtolower($ext), Registry::get('config.forbidden_file_extensions'))) {
        unset($filtered[$id]);
        $msg = fn_get_lang_var('text_forbidden_file_extension');
        $msg = str_replace('[ext]', $ext, $msg);
        fn_set_notification('E', fn_get_lang_var('error'), $msg);
        }
        if (!empty($filtered) && (!is_array($filtered[$id]) || !empty($filtered[$id]['path']) && in_array(fn_get_mime_content_type($filtered[$id]['path'], true, 'text/plain'), Registry::get('config.forbidden_mime_types')))) {
        if (!is_array($filtered[$id])) {
        $msg = fn_get_lang_var('cant_upload_file');
        } else {
        $mime = fn_get_mime_content_type($filtered[$id]['path'], true, 'text/plain');
        $msg = fn_get_lang_var('text_forbidden_file_mime');
        $msg = str_replace('[mime]', $mime, $msg);
        }
        
        fn_set_notification('E', fn_get_lang_var('error'), $msg);
        unset($filtered[$id]);
        }
        }*/
        return $filtered;
    }
    /**
     * Remove temporary files
     */
    function fn_remove_temp_data() {
        $fs_data = scandir(__DIR_EXIM . 'tmp/');
        if (!empty($fs_data)) {
            foreach ($fs_data as $file) {
                $this->fn_delete_file(__DIR_EXIM . 'tmp/' . $file);
            }
        }
    }
    /**
     * Delete file function
     *
     * @param string $file_path file location
     * @return bool true
     */
    function fn_delete_file($file_path) {
        if (!empty($file_path)) {
            if (is_file($file_path)) {
                @chmod($file_path, 0775);
                @unlink($file_path);
            }
        }
        return true;
    }
    function fn_import($pattern, $import_data, $options, $resAttributeFields = array(),$patternID='') {
        if (!empty($resAttributeFields)) {
            if (empty($import_data)) {
                $errorArray = array(
                    'error' => 'No POST data',
                    'errType' => 'input_data',
                    'errorMessage' => "No post Data found"
                );
                $this->reportError($errorArray);
            } else {
                $resourceAccess = $resAttributeFields['resourceAccess'];
                if ($resourceAccess == 'all') {
                    $allowedAttributes = array_keys($pattern['export_fields']);
                } else {
                    $allowedAttributes = $resAttributeFields['attributes'];
                }
                
                $inputFields = array_keys($import_data[0]);
                foreach ($inputFields as $field) {
                    if (in_array($field, $allowedAttributes)) {
                        continue;
                    } else {
                        $errorArray = array(
                            'error' => $field,
                            'errType' => 'no write-permission',
                            'errorMessage' => "Permission denied field '" . $field . "'"
                        );
                        $this->reportError($errorArray);
                    }
                }
            }
            if ($this->hasError()) {
                $this->showErrors();
            }
        }
        $langXml               = $this->lang_xml;
        $ObjValidate           = new Validate();
        //$ajax = Registry::get('ajax');
        $processed_data        = array(
            'E' => 0, // existent
            'N' => 0, // new
            'S' => 0 // skipped
        );
        //fn_set_hook('import_pre_moderation', $pattern, $import_data, $options, $processed_data);
        $skipped_rows          = array();
        $alt_keys              = array();
        $primary_fields        = array();
        $table_groups          = array();
        $processing_groups     = array();
        $default_groups        = array();
        $converting_groups     = array();
        $pre_inserting_groups  = array();
        $post_inserting_groups = array();
        $add_fields            = array();
        $primary_object_ids    = array();
        $required_fields       = array();
        $required_log_fields   = array();
        $validate_errors       = array();
        $validate_fields       = array();
        $alt_conditions        = array();
        $insert_ids            = array();
        if (!empty($pattern['alt_condition'])) {
            foreach ($pattern['alt_condition'] as $field => $value) {
                $alt_conditions[$field] = $value;
            }
        }
        if (!empty($pattern['pre_processing'])) {
            foreach ($pattern['pre_processing'] as $function => $args) {
                foreach ($args as $k => $v) {
                    if (strpos($v, '@') !== false) {
                        $_opt     = str_replace('@', '', $v);
                        $args[$k] = isset($options[$_opt]) ? $options[$_opt] : '';
                    }
                    if (strpos($v, '$') !== false) {
                        $_opt     = str_replace('$', '', $v);
                        $args[$k] = isset($_opt) ? $_opt : '';
                    }
                }
                call_user_func_array(array(
                    $this,
                    $function
                ), $args);
            }
        }
        if (!empty($pattern['references'])) {
            foreach ($pattern['references'] as $table => $data) {
                $table_groups[$table] = $data;
            }
        }
        // Get keys to detect primary record
        
        foreach ($pattern['export_fields'] as $field => $data) {
            $_db_field = (empty($data['db_field']) ? $field : $data['db_field']);
            // Collect fields with default values
            if (isset($data['default'])) {
                if (is_array($data['default'])) {
                    $default_groups[$_db_field] = call_user_func_array(array(
                        $this,
                        array_shift($data['default'])
                    ), $data['default']);
                } else {
                    $default_groups[$_db_field] = $data['default'];
                }
            }
            // Get alt keys for primary table
            if (!empty($data['alt_key'])) {
                $alt_keys[$field] = $_db_field;
            }
            if (!empty($data['required']) && $data['required'] = true) {
                $required_fields[]               = $_db_field;
                $required_log_fields[$_db_field] = $field;
            }
            if (!empty($data['validate'])) {
                $validate_fields[$_db_field] = $data['validate'];
                $validate_errors[$_db_field] = $data['error'];
            }
            if (!isset($data['linked']) || $data['linked'] == true) {
                // Get fields for primary table
                if (empty($data['table']) || $data['table'] == $pattern['table']) {
                    $primary_fields[$field] = $_db_field;
                }
                // Group fields by tables
                if (!empty($data['table'])) {
                    $table_groups[$data['table']]['fields'][$_db_field] = true;
                }
            }
            // Create set with fields that must be added to data import if they are not exist
            // %'s are for compatibility with %% field type in "process_put" key
            if (!empty($data['use_put_from'])) {
                $_f                = str_replace('%', '', $data['use_put_from']);
                $_f                = !empty($pattern['export_fields'][$_f]['db_field']) ? $pattern['export_fields'][$_f]['db_field'] : $_f;
                $add_fields[$_f][] = $_db_field;
            }
            // Generate processing groups
            if (!empty($data['process_put'])) {
                $args     = $data['process_put'];
                $function = array_shift($args);
                if (is_object($args[0])) {
                    $object = array_shift($args);
                } else {
                    $object = $this;
                }
                $processing_groups[] = array(
                    'function' => $function,
                    'object' => $object,
                    'args' => $args,
                    'this_field' => $_db_field,
                    'table' => !empty($data['table']) ? $data['table'] : '',
                    'return_result' => !empty($data['return_result']) ? $data['return_result'] : false
                );
            }
            // Generate converting groups
            if (!empty($data['convert_put'])) {
                $args     = $data['convert_put'];
                $function = array_shift($args);
                //updated isset
                if (isset($args[0]) && is_object($args[0])) {
                    $object = array_shift($args);
                } else {
                    $object = $this;
                }
                $converting_groups[] = array(
                    'function' => $function,
                    'object' => $object,
                    'this_field' => $_db_field,
                    'args' => $args
                );
            }
            //Generate pre inserting groups
            if (!empty($data['pre_insert'])) {
                $args     = $data['pre_insert'];
                $function = array_shift($args);
                if (is_object($args[0])) {
                    $object = array_shift($args);
                } else {
                    $object = $this;
                }
                $pre_inserting_groups[] = array(
                    'function' => $function,
                    'object' => $object,
                    'this_field' => $_db_field,
                    'args' => $args
                );
            }
            //Generate post inserting groups
            if (!empty($data['post_insert'])) {
                $args                    = $data['post_insert'];
                $function                = array_shift($args);
                $post_inserting_groups[] = array(
                    'function' => $function,
                    'this_field' => $_db_field,
                    'args' => $args
                );
            }
        }
      
      
        foreach ($import_data as $k => $v) {
            foreach ($required_fields as $field) {
                if (empty($v[$field]) && $v[$field] !== 0) {
                    $skipped_rows[$k]['lineNo'] = $k + 1;
                    //added for warning
                    if (empty($skipped_rows[$k]['field']))
                        $skipped_rows[$k]['field'] = '';
                    //added for warning
                    $skipped_rows[$k]['field'] .= $required_log_fields[$field] . ",";
                }
            }
            $skipped_rows[$k]['field'] = (isset($skipped_rows[$k]['field'])) ? trim($skipped_rows[$k]['field'], ",") : "";
            //If the required field is empty skip this record
            foreach ($required_fields as $field) {
                if (empty($v[$field]) && $v[$field] !== 0) {
                    $processed_data['S']++;
                    continue 2;
                }
            }
            if (isset($options['method']) && $options['method'] == 'post') {
                foreach ($validate_fields as $key => $validate) {
                    foreach ($validate as $ruleKey => $rules) {
                        $params = array(
                            'value' => $v[$key]
                        );
                        if (!$ObjValidate->$rules($params)) {
                            $errorArray = array(
                                'error' => $key,
                                'errType' => $rules,
                                'errorMessage' => $validate_errors[$key][$ruleKey],
                                'record' => ($k + 1)
                            );
                            $this->reportError($errorArray);
                        }
                    }
                }
            } else if (isset($options['method']) && $options['method'] == 'put') {
                foreach ($validate_fields as $key => $validate) {
                    foreach ($validate as $ruleKey => $rules) {
                        $params = array(
                            'value' => $v[$key]
                        );
                        if (!$ObjValidate->$rules($params) && in_array($key, array_keys($v))) {
                            $errorArray = array(
                                'error' => $key,
                                'errType' => $rules,
                                'errorMessage' => $validate_errors[$key][$ruleKey],
                                'record' => ($k + 1)
                            );
                            $this->reportError($errorArray);
                        }
                    }
                }
            }
            if ($this->hasError()) {
                $this->showErrors();
            }
            $_alt_keys     = array();
            $object_exists = true;
            // Check if converting groups exist and convert fields if it is so
            if (!empty($converting_groups)) {
                foreach ($converting_groups as $group) {
                    if (!isset($v[$group['this_field']])) {
                        continue;
                    }
                    $params   = array();
                    $params[] = $v[$group['this_field']];
                    foreach ($group['args'] as $arg) {
                        if (strpos($arg, '@') !== false) {
                            $_opt     = str_replace('@', '', $arg);
                            $params[] = isset($options[$_opt]) ? $options[$_opt] : '';
                        }
                    }
                    $v[$group['this_field']] = call_user_func_array(array(
                        $group['object'],
                        $group['function']
                    ), $params);
                }
            }
            foreach ($alt_keys as $import_field => $real_field) {
                if (!isset($v[$real_field])) {
                    continue;
                }
                $_alt_keys[$real_field] = $v[$real_field];
            }
            foreach ($primary_fields as $import_field => $real_field) {
                if (!isset($v[$real_field])) {
                    continue;
                }
                $_primary_fields[$real_field] = $v[$real_field];
            }
            $skip_get_primary_object_id = false;
            /**
             * Hook is used for changing query that selects primary object ID.
             *
             * @param array $pattern Array with import pattern data
             * @param array $_alt_keys Array with key=>value data of possible primary object (used for 'where' condition)
             * @param array $v Array with importing data (one row)
             * @param boolean $skip_get_primary_object_id Skip or not getting Primary object ID
             */
            //fn_set_hook('import_get_primary_object_id', $pattern, $_alt_keys, $v, $skip_get_primary_object_id);
            if ($skip_get_primary_object_id) {
                $primary_object_id = array();
            } else {
                //$primary_object_id = db_get_row('SELECT ' . implode(', ', $pattern['key']) . ' FROM ?:' . $pattern['table'] . ' WHERE '.$_alt_keys);
                $_where = '';
                foreach ($_alt_keys as $field => $value) {
                    $_where = "$field IN ('$value')";
                }
                if (!empty($pattern['alt_table']) && ($pattern['alt_table'] == 'product_options' || $pattern['alt_table'] == 'brand_details')) {
                    if ($_where != '') {
                        /*$sql='
                        SELECT 
                        ' . implode(', ', $pattern['key']) . ' 
                        FROM 
                        '.DB_PREFIX . $pattern['alt_table'] . ' 
                        WHERE 
                        '.$_where;
                        */
                        $sql = 'SELECT ' . $pattern['alt_table'] . '.' . $pattern['alt_table_key'] . ' FROM ' . DB_PREFIX . $pattern['alt_table'] . ' as ' . $pattern['alt_table'] . ' LEFT JOIN ' . DB_PREFIX . $pattern['table'] . ' as ' . $pattern['table'] . ' ON (' . $pattern['table'] . '.' . $pattern['alt_table_key'] . ' =' . $pattern['alt_table'] . '.' . $pattern['alt_table_key'] . ') WHERE 
								' . $_where;
                        if (!empty($alt_conditions)) {
                            foreach ($alt_conditions as $field => $value) {
                                if (strpos($value, '!') !== false) {
                                    $value     = str_replace('!', '', $value);
                                    $_alt_cond = "$field!='$value'";
                                } else
                                    $_alt_cond = "$field IN ('$value')";
                                $sql .= " AND " . $_alt_cond;
                            }
                        }
                        $primary_object_id = $this->ObjDatabase->readValue($sql, MYSQLI_ASSOC);
                    } else {
                        $primary_object_id = array();
                    }
                } else {
                    if ($_where != '') {
                        $sql               = '
							SELECT 
								' . implode(', ', $pattern['key']) . ' 
							FROM 
								' . DB_PREFIX . $pattern['table'] . ' 
							WHERE ' . $_where;
                        
                        $primary_object_id = $this->ObjDatabase->readValue($sql, MYSQLI_ASSOC);
                    } else {
                        $primary_object_id = array();
                    }
                }
            }
            
            $primary_object_ids[] = $primary_object_id;
            $skip_record          = false;
            //fn_set_hook('import_process_data', $primary_object_id, $v, $pattern, $options, $processed_data, $processing_groups, $skip_record);
            if (!empty($pre_inserting_groups)) {
                foreach ($pre_inserting_groups as $group) {
                    if (!isset($v[$group['this_field']])) {
                        continue;
                    }
                    $params = array();
                    foreach ($group['args'] as $arg) {
                        if (strpos($arg, '@') !== false) {
                            $_opt     = str_replace('@', '', $arg);
                            $params[] = isset($options[$_opt]) ? $options[$_opt] : '';
                        } elseif ($arg == '#this') {
                            $params[] = $v[$group['this_field']];
                        } else if (strpos($arg, '$') !== false) {
                            $_opt     = str_replace('$', '', $arg);
                            $params[] = $v[$_opt];
                        } else {
                            $params[] = $arg;
                        }
                    }
                    $params[] =& $skip_record;
                    $v[$group['this_field']] = call_user_func_array(array(
                        $group['object'],
                        $group['function']
                    ), $params);
                }
            }
            if ($this->hasError()) {
                $this->showErrors();
            }
            if ($skip_record) {
                continue;
            }
            if (!(isset($pattern['import_skip_db_processing']) && $pattern['import_skip_db_processing'])) {
                //fn_set_progress('echo', fn_get_lang_var('importing_data'));
                if (empty($primary_object_id)) {
                    // If scheme is used for update objects only, skip this record
                    if (!empty($pattern['update_only'])) {
                        $_a = array();
                        foreach ($alt_keys as $_d => $_v) {
                            if (!isset($v[$_v])) {
                                continue;
                            }
                            $_a[] = $_d . ' = ' . $v[$_v];
                        }
                        $processed_data['S']++;
                        continue;
                    }
                    $object_exists = false;
                    $processed_data['N']++;
                    // For new objects - fill the default values
                    if (!empty($default_groups)) {
                        foreach ($default_groups as $field => $value) {
                            if (empty($v[$field])) {
                                $v[$field] = $value;
                            }
                        }
                    }
                } else {
                    $processed_data['E']++;
                }
                
                if($patternID != 'product_attributes' && $patternID != 'product_custom_options') { 
                    $_data = $this->fn_check_table_fields($v, $pattern['table']);
                    if(!(int)($_data['businessID'])) {
                        $_data['businessID'] = $options['businessID'];
                    }
                } else {
                   $_data  = '';
                }     
                if($pattern['table']=='products' && !empty($_data) && $patternID == 'products') {
                    $_data['productQuantityNotifyAt'] = 1;
                }
                if(!empty($_data)) {
                    
                    if ($object_exists == true) {

                        $dtawhere = $this->update($_data, $primary_object_id, $pattern['table']);
                        $sql      = '
                                                    UPDATE 
                                                            ' . DB_PREFIX . $pattern['table'] . ' 
                                                    SET 
                                                            ' . $dtawhere['cond'] . ' 
                                                    WHERE 
                                                            ' . $dtawhere['where'];

                        $qryRun = $this->ObjDatabase->setQuery($sql);
                        if($qryRun){
                            $this->updateProductLock($_data['productStatus'],$primary_object_id['productID']);
                        }else{
                            //echo "executed failed"; exit;
                        }
                        $this->setUpdatedKeys($primary_object_id);
                    } else {

                        $insertData   = $this->insert($_data, $pattern['table']);
                        $sql          = 'INSERT INTO ' . DB_PREFIX . $pattern['table'] . $insertData;

                        $o_ids        = $this->ObjDatabase->setQuery($sql);
                        $o_id         = $this->ObjDatabase->getInsertId();
                        if($o_ids){
                            $this->updateProductLock($_data['productStatus'],$o_id);
                        }else{
                            //echo "executed failed"; exit;
                        }
                        $insert_ids[] = $o_id;
                        if ($o_id !== true) {
                            $primary_object_id = array(
                                reset($pattern['key']) => $o_id
                            );
                        } else {
                            foreach ($pattern['key'] as $_v) {
                                $primary_object_id[$_v] = $_data[$_v];
                            }
                        }
                        $this->setInsertedKeys($primary_object_id);
                    }
                }
            }
            $skip_db_processing_record = false;
            if (!empty($post_inserting_groups)) {
                foreach ($post_inserting_groups as $group) {
                    if (!isset($v[$group['this_field']])) {
                        continue;
                    }
                    $params = array();
                    foreach ($group['args'] as $arg) {
                        if (strpos($arg, '@') !== false) {
                            $_opt     = str_replace('@', '', $arg);
                            $params[] = isset($options[$_opt]) ? $options[$_opt] : '';
                        } elseif ($arg == '#this') {
                            $params[] = $v;
                        }
                    }
                    $params[] =& $skip_db_processing_record;
                    $v[$group['this_field']] = call_user_func_array(array(
                        $this,
                        $group['function']
                    ), $params);
                }
            }
            //fn_set_hook('import_after_process_data', $primary_object_id, $v, $pattern, $options, $processed_data, $processing_groups, $skip_db_processing_record);
            if ($skip_db_processing_record) {
                continue;
            }
            
            if (!empty($processing_groups)) {
                foreach ($processing_groups as $group) {
                    
                    $args           = array();
                    $use_this_group = true;
                    $_refs          = array();
                    foreach ($group['args'] as $ak => $av) {
                        
                        if (is_object($av)) {
                            $args[$ak] = $av;
                        } else if ($av == '#pk') {
                            $args[$ak] = $primary_object_id;
                        } else if ($av == '#key') {
                            $args[$ak] = (sizeof($primary_object_id) == 1) ? reset($primary_object_id) : $primary_object_id;
                        } elseif ($av == '#this') {
                            // If we do not have this field in the import data, do not apply the function
                            $this_id = $group['this_field'];
                            if($group['function']!='fn_exim_set_product_attributes' && $group['function']!='fn_exim_set_product_options') { 
                                if (!isset($v[$this_id]) ) {    

                                    $is_empty_data = true;
                                    if (!empty($add_fields[$this_id])) {
                                        foreach ($add_fields[$this_id] as $from_field) {
                                            if (isset($v[$from_field])) {
                                                $is_empty_data = false;
                                            }
                                        }
                                    }
                                    if ($is_empty_data) {
                                        $use_this_group = false;
                                        break;
                                    }
                                }
                                $args[$ak] = $v[$group['this_field']];
                            } else {      
                                $tempv     = $v;
                                unset($tempv['Product ID']);
                                unset($tempv['optionSKU']);
                                unset($tempv['businessID']);
                                unset($tempv['Product Name']);
                                $args[$ak] = $tempv;
                            }
                            
                        } elseif ($av == '#counter') {
                            $args[$ak] =& $processed_data;
                        } elseif (strpos($av, '%') !== false) {
                            $_ref      = str_replace('%', '', $av);
                            $_ref      = !empty($pattern['export_fields'][$_ref]['db_field']) ? $pattern['export_fields'][$_ref]['db_field'] : $_ref; // FIXME!!! Move to code, which builds processing_groups
                            $args[$ak] = isset($v[$_ref]) ? $v[$_ref] : '';
                            $_refs[]   = $_ref;
                        } elseif (strpos($av, '@') !== false) {
                            $_opt      = str_replace('@', '', $av);
                            $args[$ak] = $options[$_opt];
                        } elseif (strpos($av, '$') !== false) {
                            $_ref      = str_replace('$', '', $av);
                            $args[$ak] = isset($v[$_ref]) ? $v[$_ref] : '';
                            $_refs[]   = $_ref;
                        } else {
                            $args[$ak] = $av;
                        }
                    }
                    
                    if ($use_this_group == false) {                        
                        continue;
                    }
                    $result = call_user_func_array(array(
                        $group['object'],
                        $group['function']
                    ), $args); // FIXME - add checking for returned value
                    if ($group['return_result'] == true) {
                        $v[$group['this_field']] = $result;
                    } else {
                        // Remove processed fields from table groups
                        if (!empty($group['table'])) {
                            unset($table_groups[$group['table']]['fields'][$group['this_field']]);
                            foreach ($_refs as $_ref) {
                                unset($table_groups[$group['table']]['fields'][$_ref]);
                            }
                        }
                    }
                }
            }
            if (!(isset($pattern['import_skip_db_processing']) && $pattern['import_skip_db_processing'])) {
                
                // Update referenced tables
                foreach ($table_groups as $table => $tdata) {
                    if (isset($tdata['import_skip_db_processing']) && $tdata['import_skip_db_processing']) {
                        break;
                    }
                    $_data        = array();
                    // First, build condition
                    $where_insert = array();
                    // If alternative key is defined, use it
                    if (!empty($tdata['alt_key'])) {
                        foreach ($tdata['alt_key'] as $akey) {
                            if (strval($akey) == '#key') {
                                $where_insert = $this->fn_array_merge($where_insert, $primary_object_id);
                            } elseif (strpos($akey, '@') !== false) {
                                $_opt                = str_replace('@', '', $akey);
                                $where_insert[$akey] = $options[$_opt];
                            } else {
                                $where_insert[$akey] = $v[$akey];
                            }
                        }
                        // Otherwise - link by reference fields
                    } else {
                        foreach ($tdata['reference_fields'] as $field => $value) {
                            if (strval($value) == '#key') {
                                $_val = ((sizeof($primary_object_id) >= 1) ? reset($primary_object_id) : $primary_object_id);
                            } elseif (strpos($value, '@') !== false) {
                                $_opt = str_replace('@', '', $value);
                                $_val = $options[$_opt];
                            } else {
                                $_val = $value;
                            }
                            $where_insert[$field] = $_val;
                        }
                    }
                    if (!empty($tdata['fields'])) {
                        // Now, build update fields array
                        foreach ($tdata['fields'] as $import_field => $set) {
                            if (!isset($v[$import_field])) {
                                continue;
                            }
                            $_data[$import_field] = $v[$import_field];
                        }
                        
                        // Check if object exists					
                        $is_exists = $this->ObjDatabase->getField("SELECT COUNT(1) FROM " . DB_PREFIX . $table . " WHERE " . $this->whereString($where_insert));
                        if ($is_exists == true && !empty($_data)) {
                            if($options['languageID']>0){
                                $where_insert['languageID'] = $options['languageID'];
                            }                            
                            $queryUpdate = $this->update($_data, $where_insert, $table);                            
                            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . $table . " SET " . $queryUpdate['cond'] . " WHERE " . $queryUpdate['where']);
                        } elseif (empty($is_exists)) { // if reference does not exist, we should insert it anyway to avoid inconsistency
                            $_data = array_merge($_data, $where_insert);
                            if (substr($table, -8) == '_details' && isset($_data['languageID'])) {
                                $ObjLanguage = new LanguageModel();
                                $languages   = $ObjLanguage->listLanguages("", "Active");
                                // add description for all cart languages when adding object data							
                                foreach ($languages as $key => $lang_v) {
                                    $_data['languageID'] = $lang_v['languageID'];
                                    $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . $table . $this->insert($_data));
                                }
                            } else {
                                
                                $sql = "
									INSERT INTO " . DB_PREFIX . $table . $this->insert($_data);
                               
                                $this->ObjDatabase->setQuery($sql);
                            }
                        }
                    }
                }
            }
           
        }
        
        if (!empty($pattern['post_processing'])) {
            
            $func     = $pattern['post_processing'];
            $function = array_shift($func);
            $args     = $func;
            foreach ($args as $k => $v) {
                if (strpos($v, '@') !== false) {
                    $_opt     = str_replace('@', '', $v);
                    $args[$k] = isset($options[$_opt]) ? $options[$_opt] : '';
                }
                if (strpos($v, '$') !== false) {
                    $_opt     = str_replace('$', '', $v);
                    $args[$k] = isset($$_opt) ? $$_opt : '';
                }
            }
            call_user_func_array(array(
                $this,
                $function
            ), $args);
        }
        //fn_set_hook('import_complete');
        $msg                              = $langXml['text_exim_data_imported'];
        $msg                              = str_replace('[new]', $processed_data['N'], $msg);
        $msg                              = str_replace('[exist]', $processed_data['E'], $msg);
        $msg                              = str_replace('[skipped]', $processed_data['S'], $msg);
        $msg                              = str_replace('[total]', $processed_data['E'] + $processed_data['N'] + $processed_data['S'], $msg);
        $count_log                        = array();
        $count_log['new']                 = $processed_data['N'];
        $count_log['exist']               = $processed_data['E'];
        $count_log['skipped']             = $processed_data['S'];
        $count_log['total']               = $processed_data['E'] + $processed_data['N'] + $processed_data['S'];
        $this->import_status['count_log'] = $count_log;
        $this->import_status['Status']    = $msg;
        if ($processed_data['S'] > 0) {
            $this->import_status['Skipped'] = 'Y';
            $handle                         = fopen(__DIR_EXIM . "error_log.txt", 'w');
            $error_log                      = "Skipped Objects:" . $processed_data['S'] . "\n\n";
            foreach ($skipped_rows as $log) {
                if (trim($log['lineNo']) != '' && trim($log['field']) != '')
                    $error_log .= "Line No : " . $log['lineNo'] . " ( Missing Required Filelds -> " . $log['field'] . " )\n\n";
            }
            fwrite($handle, $error_log);
            fclose($handle);
        }
        if (isset($options['api']) && ($options['api'] == TRUE)) {
            if ($options['method'] == 'post') {
                $keys = $this->getInsertedKeys();
                if (!is_array($keys)) {
                    $response = array(
                        'status' => 'Failure',
                        'reason' => 'Internal Error'
                    );
                } else {
                    $response = array(
                        'response' => 'OK',
                        'responseCode' => '200',
                        'keys' => $keys
                    );
                }
            } else if ($options['method'] == 'put') {
                $keys = $this->getUpdatedKeys();
                if (!is_array($keys)) {
                    $response = array(
                        'response' => 'Failure',
                        'reason' => 'Primary field is not found in the Input data'
                    );
                } else {
                    $response = array(
                        'response' => 'OK',
                        'responseCode' => '200',
                        'keys' => $keys
                    );
                }
            }
            echo json_encode($response);
            exit;
        }
        
        return true;
    }
    //
    // Process csv file using pattern
    // Parameters:
    // @pattern - import/export pattern
    // @file - path to csv file on filesystem
    // @options - processing options
    function fn_get_csv($pattern, $file, $options) {
        
        $langXml       = $this->lang_xml;
        $handle        = fopen(__DIR_EXIM . "error_log.txt", 'w');
        $max_line_size = 16384;
        $result        = array();
        $delimiter     = ',';
        if (!empty($file) && file_exists($file)) {
            $encoding = $this->fn_detect_encoding($file, 'F', !empty($options['lang_code']) ? $options['lang_code'] : "en");
            if (!empty($encoding)) {
                $file = $this->fn_convert_encoding($encoding, 'UTF-8', $file, 'F');
            } else {
                //fn_set_notification('W', fn_get_lang_var('warning'), fn_get_lang_var('text_exim_utf8_file_format'));
                echo 'text_exim_utf8_file_format';
                $this->import_error = $langXml['error_text_exim_utf8_file_format'];
            }
            $f = false;
            if ($file !== false) {
                $f = fopen($file, 'rb');
            }
            if ($f) {
                // Get import schema
                $import_schema = fgetcsv($f, $max_line_size, $delimiter);
                if (empty($import_schema)) {
                    //fn_set_notification('E', fn_get_lang_var('error'), fn_get_lang_var('error_exim_cant_read_file'));
                    $this->import_error = $langXml['error_exim_cant_read_file'];
                    return false;
                }
                // Check if we selected correct delimiter
                // If line was read without delimition, array size will be == 1.
                if (sizeof($import_schema) == 1) {
                    
                    // we could export one column if it is correct, otherwise show error
                    if (!in_array($import_schema[0], array_keys($pattern['export_fields']))) {
                        //fn_set_notification('E', fn_get_lang_var('error'), fn_get_lang_var('error_exim_incorrent_delimiter'));
                        echo "error_exim_incorrent_delimiter";
                        $this->import_error = $langXml['error_exim_incorrent_delimiter'];
                        return false;
                    }
                }
                // Analyze schema - check for required fields
                if ($this->fn_analyze_schema($import_schema, $pattern) == false) {
                    return false;
                }
                // Collect data
                $schema_size   = sizeof($import_schema);
                $skipped_lines = array();
                $line_it       = 1;
                while (($data = $this->fn_fgetcsv($f, $max_line_size, $delimiter)) !== false) {
                    $line_it++;
                    if ($this->fn_is_empty($data)) {
                        continue;
                    }
                    if (sizeof($data) != $schema_size) {
                        $skipped_lines[] = $line_it;
                        continue;
                    }
                    $data     = $this->fn_strip_slashes($data);
                    $result[] = array_combine($import_schema, $data);
                }
                if (!empty($skipped_lines)) {
                    $msg                = $langXml['error_exim_incorrect_lines'];
                    $this->import_error = $msg = str_replace('[lines]', implode(', ', $skipped_lines), $msg);
                    fwrite($handle, $msg);
                }
                return $result;
            } else {
                //fn_set_notification('E', fn_get_lang_var('error'), fn_get_lang_var('error_exim_cant_open_file'));
                $this->import_error = $langXml['error_exim_cant_open_file'];
                return false;
            }
        } else {
            //fn_set_notification('E', fn_get_lang_var('error'), fn_get_lang_var('error_exim_file_doesnt_exist'));
            $this->import_error = $langXml['error_exim_file_doesnt_exist'];
            return false;
        }
    }
    /**
     * Detect encoding by language
     *
     * @param string $resource string or file path
     * @param string $resource_type 'S' (string) or 'F' (file)
     * @param string $lang_code language of the file characters
     * @return string  detected encoding
     */
    function fn_detect_encoding($resource, $resource_type = 'S', $lang_code = en) {
        $enc = '';
        $str = $resource;
        if ($resource_type == 'F') {
            $str = file_get_contents($resource);
            if ($str == false) {
                return $enc;
            }
        }
        if (!$this->fn_is_utf8($str)) {
            $lang_code = $this->fn_strtolower($lang_code);
            if (in_array($lang_code, array(
                'en',
                'fr',
                'es',
                'it',
                'nl',
                'da',
                'fi',
                'sv',
                'pt',
                'nn',
                'no'
            ))) {
                $enc = 'ISO-8859-1';
            } elseif (in_array($lang_code, array(
                'hu',
                'cs',
                'pl',
                'bg',
                'ro'
            ))) {
                $enc = 'ISO-8859-2';
            } elseif (in_array($lang_code, array(
                'et',
                'lv',
                'lt'
            ))) {
                $enc = 'ISO-8859-4';
            } elseif ($lang_code == 'ru') {
                $enc = fn_detect_cyrillic_charset($str);
            } elseif ($lang_code == 'ar') {
                $enc = 'ISO-8859-6';
            } elseif ($lang_code == 'el') {
                $enc = 'ISO-8859-7';
            } elseif ($lang_code == 'he') {
                $enc = 'ISO-8859-8';
            } elseif ($lang_code == 'tr') {
                $enc = 'ISO-8859-9';
            }
        } else {
            $enc = 'UTF-8';
        }
        return $enc;
    }
    /**
     * Convert encoding of string or file
     *
     * @param string $from_enc  the encoding of the initial string/file
     * @param string $to_enc  the encoding of the result string/file 
     * @param string $resource string or file path 
     * @param string $resource_type 'S' (string) or 'F' (file)
     * @return string  string or file path
     */
    function fn_convert_encoding($from_enc, $to_enc, $resource, $resource_type = 'S') {
        if (empty($from_enc) || empty($to_enc) || ($resource_type == 'F' && empty($resource))) {
            return false;
        }
        if (strtoupper($from_enc) == strtoupper($to_enc)) {
            return $resource;
        }
        $str = $resource;
        if ($resource_type == 'F') {
            $str = file_get_contents($resource);
            if ($str == false) {
                return false;
            }
        }
        $_str = false;
        if (function_exists('iconv')) {
            if (strtoupper($to_enc) == 'UCS-2') {
                $to_enc = 'UCS-2BE';
            }
            $_str = iconv($from_enc, $to_enc, $str);
        } elseif (function_exists('mb_convert_encoding')) {
            $_str = mb_convert_encoding($str, $to_enc, $from_enc);
        }
        if ($resource_type == 'F') {
            if ($_str != false) {
                $f = fopen($resource, 'wb');
                if ($f) {
                    fwrite($f, $_str);
                    fclose($f);
                    @chmod($resource, DEFAULT_FILE_PERMISSIONS);
                } else {
                    $resource = false;
                }
            }
            return $resource;
        } else {
            return $_str;
        }
    }
    //
    // Analyze import schema and convert fields using pattern
    // Parameters:
    // @schema - import schema
    // @pattern - import/export pattern
    function fn_analyze_schema(&$schema, $pattern) {
        $langXml       = $this->lang_xml;
        $failed_fields = array();
        $schema_match  = false;
        array_walk($schema, array(
            $this,
            'fn_trim_helper'
        ));
        foreach ($pattern['export_fields'] as $field => $data) {
            if (!empty($data['required']) && $data['required'] == true && !in_array($field, $schema)) {
                $failed_fields[] = $field;
            }
            if (in_array($field, $schema)) {
                $schema_match = true;
            }
            // Replace fields aliases with database representation
            if (!empty($data['db_field'])) {
                $key = array_search($field, $schema);
                if ($key !== false) {
                    $schema[$key] = $data['db_field'];
                }
            }
        }
        if (!empty($failed_fields)) {
            //$msg = "error_exim_pattern_required_fields";			
            $msg                = $langXml['error_exim_pattern_required_fields'];
            $msg                = str_replace('[fields]', implode(', ', $failed_fields), $msg);
            $this->import_error = $msg;
            //fn_set_notification('E', fn_get_lang_var('error'), $msg);
            return false;
        }
        if ($schema_match == false) {
            echo "error_exim_pattern_dont_match";
            //fn_set_notification('E', fn_get_lang_var('error'), fn_get_lang_var('error_exim_pattern_dont_match'));
            $this->import_error = $langXml['error_exim_pattern_dont_match'];
            return false;
        }
        return true;
    }
    /**
     * Gets line from file pointer and parse for CSV fields
     *
     * @param handle $f a valid file pointer to a file successfully opened by fopen(), popen(), or fsockopen().
     * @param int $length maximum line length
     * @param string $d field delimiter
     * @param string $q the field enclosure character
     * @return array structured data
     */
    function fn_fgetcsv($f, $length, $d = ',', $q = '"') {
        $list = array();
        $st   = fgets($f, $length);
        if ($st === false || $st === null) {
            return $st;
        }
        if (trim($st) === '') {
            return array(
                ''
            );
        }
        $st = rtrim($st, "\n\r");
        if (substr($st, -strlen($d)) == $d) {
            $st .= '""';
        }
        while ($st !== '' && $st !== false) {
            if ($st[0] !== $q) {
                // Non-quoted.
                list($field) = explode($d, $st, 2);
                $st = substr($st, strlen($field) + strlen($d));
            } else {
                // Quoted field.
                $st    = substr($st, 1);
                $field = '';
                while (1) {
                    // Find until finishing quote (EXCLUDING) or eol (including)
                    preg_match("/^((?:[^$q]+|$q$q)*)/sx", $st, $p);
                    $part    = $p[1];
                    $partlen = strlen($part);
                    $st      = substr($st, strlen($p[0]));
                    $field .= str_replace($q . $q, $q, $part);
                    if (strlen($st) && $st[0] === $q) {
                        // Found finishing quote.
                        list($dummy) = explode($d, $st, 2);
                        $st = substr($st, strlen($dummy) + strlen($d));
                        break;
                    } else {
                        // No finishing quote - newline.
                        $st = fgets($f, $length);
                    }
                }
            }
            $list[] = $field;
        }
        return $list;
    }
    function fn_exim_put_product_combination($product_sku, $combination_code, $combination, $amount, $price_impact, $quantity, &$counter, $lang_code = '1', $bar_code, $status, $businessID = '') {
        $object_id      = $this->ObjDatabase->getField("SELECT productID FROM " . DB_PREFIX . "product_combination WHERE combinationSKU ='" . $this->fn_html_entity_encode($combination_code) . "' AND  status!='D'");
        $pair_delimiter = ':';
        $set_delimiter  = ',';
        if (!empty($combination)) {
            // Get product_id
            $object_id = 0;
            if (!empty($product_sku)) {
                $resOpt_id = $this->ObjDatabase->readValue("SELECT do.productID FROM " . DB_PREFIX . "product_options do LEFT JOIN
								  " . DB_PREFIX . "products d ON(do.productID=d.productID) WHERE do.optionSKU='" . $product_sku . "' AND do.productOptionStatus!='Delete' AND do.productOptionDefault='Yes' AND d.businessID=" . $businessID . " AND d.productStatus!='Deleted'");
                if (empty($object_id))
                    $object_id = $resOpt_id['productID'];
            }
            if (empty($object_id) && !empty($product_name)) {
                $object_id = $this->ObjDatabase->getField('SELECT productID FROM ' . DB_PREFIX . 'product_details DD
									 INNER JOIN
								  ".DB_PREFIX."products d ON(DD.productID=d.productID) WHERE 
									 WHERE productTitle =' . $product_name . ' d.businessID=' . $businessID . ' AND  languageID =' . $lang_code);
            }
            if (empty($object_id)) {
                $counter['S']++;
                return false;
            }
            $options = explode($set_delimiter, $combination);
            if (!empty($options)) {
                $_combination = array();
                foreach ($options as $option_pair) {
                    $pair = explode($pair_delimiter, $option_pair);
                    if (is_array($pair)) {
                        array_walk($pair, array(
                            $this,
                            'fn_trim_helper'
                        ));
                        $option_ids    = $this->ObjDatabase->readValue("SELECT OD.`customOptionID` FROM " . DB_PREFIX . "product_custom_option_details OD LEFT JOIN " . DB_PREFIX . "product_custom_option O ON(OD.`customOptionID`=O.`customOptionID`)
									      LEFT JOIN " . DB_PREFIX . "product_custom_option_link as L on(L.`customOptionID`=OD.`customOptionID`) WHERE OD.`languageID`=" . $lang_code . " AND
						`customOptionName`='" . $this->fn_html_entity_encode($pair[0]) . "' AND L.productID='" . $object_id . "'");
                        $option_id     = $option_ids['customOptionID'];
                        /*if (empty($option_id)) {						
                        
                        $resoption_id = $this->ObjDatabase->readValue("SELECT o.customOptionID FROM ".DB_PREFIX."product_custom_option_details as d INNER JOIN ".DB_PREFIX."product_custom_option as o ON o.customOptionID = d.customOptionID
                        WHERE d.customOptionName ='". $this->fn_html_entity_encode($pair[0])."' AND  languageID=". $lang_code);
                        $option_id=$resoption_id['customOptionID'];
                        }*/
                        $resvariant_id = $this->ObjDatabase->readValue("SELECT v.customOptionVariantID FROM " . DB_PREFIX . "product_custom_option_variant_details as d INNER JOIN " . DB_PREFIX . "product_custom_option_variant as v
											    ON v.customOptionVariantID = d.customOptionVariantID AND v.customOptionID ='" . $option_id . "' WHERE d.value = '" . $this->fn_html_entity_encode($pair[1]) . "' AND d.languageID ='" . $lang_code . "' LIMIT 1");
                        $variant_id    = $resvariant_id['customOptionVariantID'];
                        if (empty($option_id) || empty($variant_id)) {
                            $counter['S']++;
                            return false;
                        }
                        $_combination[$option_id] = $variant_id;
                    }
                }
                $combination      = $this->fn_get_options_combination($_combination);
                $combination      = $object_id . "_" . $combination;
                //$combination_hash = fn_generate_cart_id($object_id, array('product_options' => $_combination));
                $combination_hash = $this->makeHAsh($combination);
                $object_details   = $this->ObjDatabase->readValue("SELECT COUNT(*) as count,combinationID, combinationPrice FROM " . DB_PREFIX . "product_combination proCombo
										LEFT JOIN  `" . DB_PREFIX . "products` products
						ON(proCombo.productID=products.productID) WHERE products.businessID=" . $businessID . " AND combinationSKU = '" . $combination_code . "' AND status!='D'");
                if ($object_details['count'] > 0) {
                    $combinationID = $object_details['combinationID'];
                    if ($status == '')
                        $status = 'A';
                    if (($object_details['amount'] <= 0) && ($_data['amount'] > 0)) {
                        //fn_send_product_notifications($object_id);
                    }
                    $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_combination SET
								     productID='" . $object_id . "',							    
								     combination='" . $combination . "',
								     combinationHash ='" . $combination_hash . "',
								     combinationPrice='" . $amount . "',
								      	combinationBarCode='" . $bar_code . "',
									combinationPriceDiffType='" . $price_impact . "',
								      combinationQty='" . $quantity . "',
								      Status='" . $status . "'
								     WHERE  combinationID=" . $combinationID . " AND combinationSKU='" . $this->fn_html_entity_encode($combination_code) . "'");
                    //fn_set_progress('echo', fn_get_lang_var('updating') . ' ' . fn_get_lang_var('product_combinations') . '...', false);
                    $counter['E']++;
                } else {
                    $price_impact = empty($price_impact) ? 'N' : $price_impact;
                    $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_combination(
				`productID`, `combination`, `combinationHash`, `combinationSKU`,`combinationBarCode`,`combinationPrice`,`combinationPriceDiffType`,`combinationQty`,`status`
				)
				VALUES 
				( 
				'" . $object_id . "',
				'" . $combination . "',
				'" . $combination_hash . "',
				'" . $this->escape($combination_code) . "',
				'" . $bar_code . "',				
				'" . $amount . "',
				'" . $price_impact . "',
				'" . $quantity . "',
                                '" . $status . "')");
                    //fn_set_progress('echo', fn_get_lang_var('creating') . ' ' . fn_get_lang_var('product_combinations') . '...', false);
                    $counter['N']++;
                }
                //fn_set_progress('echo', '<b>' . $object_id . '</b>.<br />', false);
                return $combination;
            }
        }
        $counter['S']++;
        return false;
    }
    function fn_get_options_combination($product_options) {
        if (empty($product_options) && !is_array($product_options)) {
            return '';
        }
        /*$combination = '';
        foreach ($product_options as $option => $variant) {
        $combination .= $option . '_' . $variant . '_';
        }*/
        $combination = implode('_', $product_options);
        $combination = trim($combination, '_');
        return $combination;
    }
    /**
     * Check whether string is UTF-8 encoded
     *
     * @param string $str 
     * @return boolean
     */
    function fn_is_utf8($str) {
        $c    = 0;
        $b    = 0;
        $bits = 0;
        $len  = strlen($str);
        for ($i = 0; $i < $len; $i++) {
            $c = ord($str[$i]);
            if ($c > 128) {
                if (($c >= 254)) {
                    return false;
                } elseif ($c >= 252) {
                    $bits = 6;
                } elseif ($c >= 248) {
                    $bits = 5;
                } elseif ($c >= 240) {
                    $bits = 4;
                } elseif ($c >= 224) {
                    $bits = 3;
                } elseif ($c >= 192) {
                    $bits = 2;
                } else {
                    return false;
                }
                if (($i + $bits) > $len) {
                    return false;
                }
                while ($bits > 1) {
                    $i++;
                    $b = ord($str[$i]);
                    if ($b < 128 || $b > 191) {
                        return false;
                    }
                    $bits--;
                }
            }
        }
        return true;
    }
    function fn_trim_helper(&$value) {
        $value = is_string($value) ? trim($value) : $value;
    }
    function fn_strip_slashes($var) {
        if (is_array($var)) {
            $var = array_map(array(
                $this,
                'fn_strip_slashes'
            ), $var);
            return $var;
        }
        return (strpos($var, '\\\'') !== false || strpos($var, '\\\\') !== false || strpos($var, '\\"') !== false) ? stripslashes($var) : $var;
    }
    function fn_check_table_fields($data, $table_name) {
        $_fields = array();
        $fields  = $this->ObjDatabase->readValues("SHOW COLUMNS FROM " . DB_PREFIX . $table_name);
        foreach ($fields as $key => $val) {
            $_fields[] = $val['Field'];
        }
        if (is_array($_fields)) {
            foreach ($data as $k => $v) {
                if (!in_array($k, $_fields)) {
                    unset($data[$k]);
                }
            }
            if (func_num_args() > 3) {
                for ($i = 3; $i < func_num_args(); $i++) {
                    unset($data[func_get_arg($i)]);
                }
            }
            return $data;
        }
        return false;
    }
    function update($dta, $where, $table = '') {
        $whereString  = '1';
        $updateString = '';
        foreach ($dta as $key => $val) {
            if ($val !== '')
                $val = "'" . $this->fn_html_entity_encode($val) . "'";
            else {
                if ($table) {
                    $default = $this->ObjDatabase->readValue("SHOW COLUMNS FROM " . DB_PREFIX . $table . " WHERE Field =  '" . $key . "' ");
                    $val     = ($default['Null'] == 'NO') ? "'$val'" : 'NULL';
                } else
                    $val = "''";
            }
            $updateString .= "`" . $key . "`=" . $val . ",";
        }
        $updateString = trim($updateString, ",");
        if ($where) {
            foreach ($where as $key => $val) {
                $whereString .= " AND `" . $key . "`='" . $this->fn_html_entity_encode($val) . "'";
            }
        }
        $cond['cond']  = $updateString;
        $cond['where'] = $whereString;
        return $cond;
    }
    function whereString($where) {
        $whereString = '1';
        if ($where) {
            foreach ($where as $key => $val) {
                $whereString .= " AND `" . $key . "`='" . $this->fn_html_entity_encode($val) . "'";
            }
        }
        return $whereString;
    }
    function insert($dta, $table = '') {
        $fields = '(';
        $values = '(';
        foreach ($dta as $key => $val) {
            if ($val != '') {
                $val = "'" . $this->fn_html_entity_encode($val) . "'";
            } else if ($val == '') {
                if ($table) {
                    $default = $this->ObjDatabase->readValue("SHOW COLUMNS FROM " . DB_PREFIX . $table . " WHERE Field =  '" . $key . "' ");
                    $val     = ($default['Null'] == 'NO') ? "'$val'" : 'NULL';
                } else
                    $val = "''";
            }
            $fields .= "`" . $key . "`,";
            $values .= $val . ",";
        }
        $fields = trim($fields, ",") . ")";
        $values = trim($values, ",") . ")";
        return $fields . " VALUES " . $values;
    }
    function fn_date_to_save($date) {
        if ($date != '') {
            $d         = str_replace('/', '-', $date);
            $date_save = date('Y-m-d', strtotime($d));
            if ($date_save == '1970-01-01')
                return '0000-00-00';
            else
                return $date_save;
        } else
            return '0000-00-00';
    }
    function fn_remove_exim_data() {
        $fs_data = scandir(__DIR_EXIM . '/');
        if (!empty($fs_data)) {
            foreach ($fs_data as $file) {
                if (substr($file, -4) == ".csv")
                    $this->fn_delete_file(__DIR_EXIM . '/' . $file);
            }
        }
    }
    function fn_exim_set_attributeID($attributeName) {
        $attributeName = $this->fn_html_entity_encode(trim($attributeName));
        $result        = $this->ObjDatabase->readValue("SELECT attributeSetID FROM " . DB_PREFIX . "attribute_set WHERE attributeSetName='" . $attributeName . "'");
        return $result['attributeSetID'];
    }
    function fn_exim_set_businessID($product_id, $businessID, $langCode, $productUrl = '', $productName = '') {
        
        /*$businessName=$this->fn_html_entity_encode(trim($businessName));
        $result = $this->ObjDatabase->readValue("SELECT bus.businessID,businessKey FROM ".DB_PREFIX."business_details as busDet  LEFT JOIN ".DB_PREFIX."business bus ON busDet.businessID = bus.businessID WHERE languageID='".$langCode."' AND businessName='".$businessName."'");*/
        
        $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET businessID='" . $businessID . "' WHERE productID ='" . $product_id . "'");        
        if (empty($productUrl)) {
            $productName = html_entity_decode($productName);
            $productUrl  = $this->fn_generate_productUrl($productName);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET productUrl='" . $productUrl . "' WHERE productID ='" . $product_id . "'");
        }
        //echo '<br><br>';print_r($result);exit;
    }
    function fn_exim_export_oname($product_id) {
        $multi_enable = $this->ObjDatabase->getField("SELECT multiOptionsAvailable FROM " . DB_PREFIX . "products WHERE  productID='" . $product_id . "' AND productStatus!='Deleted'");
        if ($multi_enable == 'Yes') {
            $result = $this->ObjDatabase->readValue("SELECT DOD.productOptionName FROM " . DB_PREFIX . "product_options DO LEFT JOIN " . DB_PREFIX . "product_option_details DOD ON(DOD.productOptionID=DO.productOptionID) WHERE  DO.productID='" . $product_id . "' AND DO.productOptionDefault='Yes'");
            return $this->fn_html_entity_decode($result['productOptionName']);
        } else
            return "";
    }
    function fn_exim_set_oname($product_id, $optionName, $optionSku, $langCode, $product_name,$listprice='',$price='',$dealPrice='',$quantity='',$barcode='',$businessID='') {
        if (empty($optionSku))
            return false;
        $ObjLanguage  = new LanguageModel();
        $resLanguages = $ObjLanguage->listLanguages("", "Active");
        if ($optionName != '')
            $optionName = trim($optionName);
        else
            $optionName = trim($product_name);
        $option_detail_data['productOptionName'] = $optionName;
        $sql                                     = "SELECT opt.productOptionID FROM " . DB_PREFIX . "product_options opt Join " . DB_PREFIX . "products product ON (opt.productID=product.productID) WHERE  opt.productOptionStatus!='Delete' AND opt.optionSKU='" . $optionSku . "'";
//        if($businessID!='') {
//            $sql                                 .= " AND product.businessID='".$businessID."'";
//        }
        $option_id                               = $this->ObjDatabase->getField($sql);
        
        if ($option_id) {
            
            $option_data['productID']            = $product_id;
            $option_data['optionSKU']            = $optionSku;
            if($price!='') {
                $option_data['productOptionRegularPrice']   = $price;
            }
            if($listprice!='') {
                $option_data['productOptionProductPrice']   = $listprice;
            }
            if($dealPrice!='') {
                $option_data['dealPrice'] = $dealPrice;
            }
            if($quantity!='') {
                $option_data['productOptionQuantity']       = $quantity;
            }
            if($barcode!='') {
                $option_data['optionBarCode']               = $barcode;
            }
            
            $where['productOptionID']              = $option_id;
            
            $upString                              = $this->update($option_data, $where);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_options SET " . $upString['cond'] . " WHERE " . $upString['where']);
            $option_detail_data['productOptionID'] = $option_id;
            $result_option                         = $this->ObjDatabase->readValue("SELECT productOptionName FROM " . DB_PREFIX . "product_option_details WHERE  productOptionID ='" . $option_id . "'AND languageID='" . $langCode . "'");
            if (!empty($result_option['productOptionName'])) {
                $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_option_details SET  productOptionName='" . $this->fn_html_entity_encode($optionName) . "' WHERE languageID='" . $langCode . "' AND productOptionID ='" . $option_id . "'");
            } else {
                $option_detail_data['languageID'] = $langCode;
                $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "product_option_details" . $this->insert($option_detail_data));
            }
            
        } else {
            
            
            $option_data['productID']            = $product_id;
            $option_data['optionSKU']            = $optionSku;
            if($price!='') {
                $option_data['productOptionRegularPrice'] = $price;
            }
            if($listprice!='') {
                $option_data['productOptionProductPrice'] = $listprice;
            }
            if($dealPrice!='') {
                $option_data['dealPrice'] = $dealPrice;
            }
            if($quantity!='') {
                $option_data['productOptionQuantity'] = $quantity;
            }
            if($barcode!='') {
                $option_data['optionBarCode']         = $barcode;
            }
            $option_data['productOptionDefault'] = 'Yes';
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_options" . $this->insert($option_data));
            $option_detail_data['productOptionID'] = $option_id = $this->ObjDatabase->getInsertId();
            
            foreach ($resLanguages as $key => $_v) {
                $option_detail_data['languageID'] = $_v['languageID'];
                $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_option_details" . $this->insert($option_detail_data));
            }
            
        }
        
        
        $sql                                     = "SELECT optBus.productOptionBusinessID 
                                                    FROM " . DB_PREFIX . "products_options_business optBus 
                                                    WHERE optBus.productOptionID='" . $option_id . "'
                                                    AND optBus.busProductStatus!='Delete'
                                                    AND optBus.businessID='".$businessID."'";
        
        $option_bus_id                           = $this->ObjDatabase->getField($sql);
        
        if($option_bus_id>0){
            $option_bus_data['businessOptionSKU']    = $optionSku;
            if($price!='') {
                $option_bus_data['productOptionRegularPrice'] = $price;
            }
            if($listprice!='') {
                $option_bus_data['productOptionProductPrice'] = $listprice;
            }
            if($dealPrice!='') {
                $option_bus_data['dealPrice'] = $dealPrice;
            }
            if($quantity!='') {
                $option_bus_data['productOptionQuantity'] = $quantity;
                $option_bus_data['productQuantityUnlimited'] = 0;
            }else{
                $option_bus_data['productOptionQuantity'] = 0;
                $option_bus_data['productQuantityUnlimited'] = 1;
            }
            
            $whereBusOpt['productOptionID']              = $option_id;
            
            $upStringBusOpt                              = $this->update($option_bus_data, $whereBusOpt);
            
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products_options_business SET " . $upStringBusOpt['cond'] . " WHERE productOptionID = '".$option_id."' AND businessID = '".$businessID."'");
        }else{
            $option_bus_data['productOptionID']      = $option_id;
            $option_bus_data['businessID']           = $businessID;
            $option_bus_data['businessOptionSKU']    = $optionSku;
            if($price!='') {
                $option_bus_data['productOptionRegularPrice'] = $price;
            }
            if($listprice!='') {
                $option_bus_data['productOptionProductPrice'] = $listprice;
            }
            if($dealPrice!='') {
                $option_bus_data['dealPrice'] = $dealPrice;
            }
            if($quantity!='') {
                $option_bus_data['productOptionQuantity'] = $quantity;
                $option_bus_data['productQuantityUnlimited'] = 0;
            }else{
                $option_bus_data['productOptionQuantity'] = 0;
                $option_bus_data['productQuantityUnlimited'] = 1;
            }
            
            $option_bus_data['busProductStatus'] = 'Active';
            $option_bus_data['businessOptionDefault'] = 'Yes';
            
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "products_options_business" . $this->insert($option_bus_data));
        }
    }
    function fn_update_product_variant($option_data, $option_id = 0, $lang_code) {
        $ObjLanguage                             = new LanguageModel();
        $resLanguages                            = $ObjLanguage->listLanguages("", "Active");
        $option_datas                            = array();
        $option_detail_data                      = array();
        $option_datas['optionSKU']               = $option_data['option_sku'];
        $option_datas['productID']               = $option_data['product_id'];
        $option_detail_data['productOptionName'] = $option_data['option_name'];
        if (!empty($option_data['variants'])) {
            foreach ($option_data['variants'] as $k => $v) {
                if ((!isset($v['variant_name']) || $v['variant_name'] == '')) {
                    continue;
                }
                if (($pos = strpos($v['variant_name'], '(')) !== false) { // option has variants
                    $variants = substr($v['variant_name'], $pos + 1, strlen($v['variant_name']) - $pos - 2);
                    $variants = explode("/", $variants);
                }
                if (substr($v['variant_name'], 0, 1) == 'P') {
                    $option_datas['productOptionRegularPrice'] = $variants[0];
                    $option_datas['productOptionProductPrice'] = $variants[1];
                } elseif (substr($v['variant_name'], 0, 1) == 'B') {
                    $option_datas['packageLength'] = $variants[0];
                    $option_datas['packageWidth']  = $variants[1];
                    $option_datas['packageHeight'] = $variants[2];
                    $option_datas['packageWeight'] = $variants[3];
                } elseif (substr($v['variant_name'], 0, 1) == 'Q') {
                    $option_datas['productOptionQuantity'] = $variants[0];
                } elseif (substr($v['variant_name'], 0, 1) == 'C') {
                    $option_datas['optionBarCode'] = $variants[0];
                }
                $option_datas['productOptionDefault'] = 'No';
                $option_datas['productOptionStatus']  = 'Active';
            }
        }
        // Add option
        if (empty($option_id)) {
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_options" . $this->insert($option_datas));
            $option_detail_data['productOptionID'] = $option_id = $this->ObjDatabase->getInsertId();
            foreach ($resLanguages as $key => $_v) {
                $option_detail_data['languageID'] = $_v['languageID'];
                $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_option_details" . $this->insert($option_detail_data));
            }
            $create = true;
            // Update option
        } else {
            $option_detail_data['productOptionID'] = $option_id;
            $where['productOptionID']              = $option_id;
            $upString                              = $this->update($option_datas, $where);
            $where['languageID']                   = $lang_code;
            $dataString                            = $this->update($option_detail_data, $where);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_options SET " . $upString['cond'] . " WHERE " . $upString['where']);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_option_details SET " . $dataString['cond'] . " WHERE " . $dataString['where']);
        }
        return $option_id;
    }
    function fn_update_product_shipping($option_data, $shipping_id = 0, $lang_code) {
        $option_datas                      = array();
        $option_detail_data                = array();
        $option_datas['shippingServiceID'] = $this->getShipServiceID($option_data['option_name']);
        if (!empty($option_data['variants'])) {
            foreach ($option_data['variants'] as $k => $v) {
                if ((!isset($v['variant_name']) || $v['variant_name'] == '')) {
                    continue;
                }
                if (($pos = strpos($v['variant_name'], '(')) !== false) { // option has variants
                    $variants = substr($v['variant_name'], $pos + 1, strlen($v['variant_name']) - $pos - 2);
                }
                if (substr($v['variant_name'], 0, 2) == 'DZ') {
                    $dstring = (!empty($variants)) ? explode('/', $variants) : array();
                    $zones   = (!empty($dstring)) ? $this->getZoneIDs($dstring) : array();
                } elseif (substr($v['variant_name'], 0, 2) == 'BC') {
                    $option_datas['baseCharge'] = $variants;
                } elseif (substr($v['variant_name'], 0, 2) == 'MQ') {
                    $option_datas['maxQtyPerShipping'] = $variants;
                } elseif (substr($v['variant_name'], 0, 2) == 'EC') {
                    $option_datas['chargePerExtraQty'] = $variants;
                } elseif (substr($v['variant_name'], 0, 2) == 'HC') {
                    $option_datas['handlingCharge'] = $variants;
                } elseif (substr($v['variant_name'], 0, 2) == 'TX') {
                    $option_datas['taxClassID'] = $this->gettaxClassID($variants);
                }
            }
        }
        // Add option
        if (empty($shipping_id)) {
            $option_datas['productID']    = $option_data['product_id'];
            $option_datas['AssignedDate'] = $option_datas['ModifiedDate'] = date("Y-m-d H:i:s");
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "shipping_to_product" . $this->insert($option_datas));
            $option_detail_data['shippingtoproductID'] = $shipping_id = $this->ObjDatabase->getInsertId();
            $create                                    = true;
            // Update option
        } else {
            $option_datas['ModifiedDate']              = date("Y-m-d H:i:s");
            $option_detail_data['shippingtoproductID'] = $shipping_id;
            $where['shippingtoproductID']              = $shipping_id;
            $upString                                  = $this->update($option_datas, $where);
            $sql                                       = "UPDATE " . DB_PREFIX . "shipping_to_product SET " . $upString['cond'] . "
										 WHERE " . $upString['where'];
            $this->ObjDatabase->setQuery($sql);
            $this->ObjDatabase->setQuery("DELETE FROM  " . DB_PREFIX . "product_to_shipping_deliveryzone
									 WHERE shippingtoproductID=" . $shipping_id);
        }
        if (!empty($zones)) {
            array_walk($zones, array(
                $this,
                'fn_trim_helper'
            ));
            foreach ($zones as $key => $zone) {
                $option_detail_data['deliveryZoneID'] = $zone['deliveryZoneID'];
                $this->ObjDatabase->setQuery("INSERT INTO
													 " . DB_PREFIX . "product_to_shipping_deliveryzone" . $this->insert($option_detail_data));
            }
        }
        return $shipping_id;
    }
    function getZoneIDs($zones) {
        return $this->ObjDatabase->readValues("SELECT  `deliveryZoneID` 
													FROM  `" . DB_PREFIX . "deliveryzone_details` 
													WHERE  `languageID` ='1'
													AND  `deliveryZoneName` 
													IN ('" . implode("','", $zones) . "')", MYSQLI_ASSOC);
    }
    function getShipServiceID($name) {
        return $this->ObjDatabase->getField("SELECT settingsGroupID 
											FROM  `" . DB_PREFIX . "shipping_methods` 
											WHERE  `settingsGroupXmlLabel` =  '" . $name . "' AND isAvailable='Yes'
											AND settingsGroupStatus='Active'");
    }
    /**
     * Deletes options and their variants by option identifier
     *
     * @param int $option_id Option identifier
     * @param int $pid Identifier of the product from which the option should be removed (for global options)
     * @return bool True on success, false otherwise
     */
    function fn_delete_product_option($option_id, $pid = 0) {
        if (!empty($option_id)) {
            // Product option
            $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_option_details WHERE productOptionID =" . $option_id);
            $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_options  WHERE productOptionID =" . $option_id);
            $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_media  WHERE  productObjectType='DO' AND productObjectID =" . $option_id);
            //fn_delete_product_option_variants($option_id);
            return true;
        }
        return false;
    }
    /**
     * Deletes options and their variants by option identifier
     *
     * @param int $option_id Option identifier
     * @param int $pid Identifier of the product from which the option should be removed (for global options)
     * @return bool True on success, false otherwise
     */
    function fn_delete_product_shipping($option_id, $pid = 0) {
        if (!empty($option_id)) {
            // Product option
            $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "shipping_to_product WHERE shippingtoproductID =" . $option_id);
            return true;
        }
        return false;
    }
    /**
     * Update product option
     *
     * @param array $option_data option data array
     * @param int $option_id option ID (empty if we're adding the option)
     * @param string $lang_code language code to add/update option for
     * @return int ID of the added/updated option
     */
    function fn_update_product_option($option_data, $option_id = 0, $lang_code = '') {
        $product_id                             = $option_data['product_id'];
        /**
         * Changes parameters before update option data
         *
         * @param array $option_data Option data
         * @param int $option_id Option identifier
         * @param string $lang_code Two-letter language code (e.g. 'en', 'ru', etc.)
         */
        $ObjCustom                              = new CustomOptionModel();
        $inputKeys                              = $ObjCustom->getInputShortKeys();
        $ObjLanguage                            = new LanguageModel();
        $resLanguages                           = $ObjLanguage->listLanguages("", "Active");
        // Add option
        $option_datas['isGlobal']               = $option_data['isGlobal'];
        $option_datas['inputType']              = array_search($option_data['option_type'], $inputKeys);
        $option_detail_data['customOptionName'] = $option_data['option_name'];
        if (empty($option_id)) {
            $option_datas['status']        = 'A';
            $option_datas['priceDiffType'] = 'N';
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_custom_option" . $this->insert($option_datas));
            $option_detail_data['customOptionID'] = $option_id = $this->ObjDatabase->getInsertId();
            foreach ($resLanguages as $key => $_v) {
                $option_detail_data['languageID'] = $_v['languageID'];
                $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_custom_option_details" . $this->insert($option_detail_data));
            }
            $create = true;
            // Update option
        } else {
            $where['customOptionID'] = $option_id;
            $upString                = $this->update($option_datas, $where);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_custom_option SET " . $upString['cond'] . " WHERE " . $upString['where']);
            $where['languageID'] = $lang_code;
            $dataString          = $this->update($option_detail_data, $where);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_custom_option_details SET " . $dataString['cond'] . " WHERE " . $dataString['where']);
        }
        if (!empty($option_data['variants'])) {
            $var_ids        = array();
            // Generate special variants structure for checkbox (2 variants, 1 hidden)
            /*if ($option_data['option_type'] == 'C') {
            $option_data['variants'] = array_slice($option_data['variants'], 0, 1); // only 1 variant should be here
            reset($option_data['variants']);
            $_k = key($option_data['variants']);
            $option_data['variants'][$_k]['position'] = 1; // checked variant
            $v_ids = $this->ObjDatabase->readValue("SELECT customOptionVariantID FROM ".DB_PREFIX."product_custom_option_variant WHERE customOptionID =".$option_id);
            $v_id=$v_ids['customOptionVariantID'];
            $option_data['variants'][] = array ( // unchecked variant
            'position' => 0,
            'variant_id' => $v_id
            );
            }*/
            $variant_images = array();
            foreach ($option_data['variants'] as $k => $v) {
                if ((!isset($v['variant_name']) || $v['variant_name'] == '') && $option_data['option_type'] != 'C') {
                    continue;
                }
                // Update product options variants
                if (isset($v['modifier'])) {
                    $v['modifier'] = floatval($v['modifier']);
                    if (floatval($v['modifier']) > 0) {
                        $v['modifier'] = '+' . $v['modifier'];
                    }
                }
                if (isset($v['weight_modifier'])) {
                    $v['weight_modifier'] = floatval($v['weight_modifier']);
                    if (floatval($v['weight_modifier']) > 0) {
                        $v['weight_modifier'] = '+' . $v['weight_modifier'];
                    }
                }
                $v['option_id'] = $option_id;
                if (!empty($v['variant_id']))
                    $result = $this->ObjDatabase->readValue("SELECT customOptionVariantID FROM " . DB_PREFIX . "product_custom_option_variant WHERE customOptionVariantID =" . $v['variant_id']);
                $variantArry                   = array();
                $variant_data                  = array();
                $where1                        = array();
                $variant_data['value']         = $v['variant_name'];
                $variantArry['customOptionID'] = $v['option_id'];
                $variantArry['status']         = 'A';
                if (empty($v['variant_id']) || (!empty($v['variant_id']) && !$result['customOptionVariantID'])) {
                    $variantArry['sortOrder']      = $v['position'];
                    $variantArry['weightDiff']     = 0;
                    $variantArry['priceDiffType']  = 'N';
                    $variantArry['weightDiffType'] = 'N';
                    $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_custom_option_variant" . $this->insert($variantArry));
                    $var_ids[] = $variant_data['customOptionVariantID'] = $v['variant_id'] = $this->ObjDatabase->getInsertId();
                    foreach ($resLanguages as $key => $_v) {
                        $variant_data['languageID'] = $_v['languageID'];
                        $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_custom_option_variant_details" . $this->insert($variant_data));
                    }
                } else {
                    $var_ids[] = $where1['customOptionVariantID'] = $v['variant_id'];
                    $upString1 = $this->update($variantArry, $where1);
                    $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_custom_option_variant SET " . $upString1['cond'] . " WHERE " . $upString1['where']);
                    $where1['languageID'] = $lang_code;
                    $dataString1          = $this->update($variant_data, $where1);
                    $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_custom_option_variant_details SET " . $dataString1['cond'] . " WHERE " . $dataString1['where']);
                }
                if ($option_data['option_type'] == 'C') {
                    //fn_delete_image_pairs($v['variant_id'], 'variant_image'); // force deletion of variant image for "checkbox" option
                } else {
                    $variant_images[$k] = $v['variant_id'];
                }
            }
            if ($option_data['option_type'] != 'C' && !empty($variant_images)) {
                //fn_attach_image_pairs('variant_image', 'variant_image', 0, $lang_code, $variant_images);
            }
            if (!empty($var_ids))
                $var_idString = implode("','", $var_ids);
            // Delete obsolete variants
            $condition        = !empty($var_ids) ? " AND customOptionVariantID NOT IN ('" . $var_idString . "')" : '';
            $deleted_variants = $this->ObjDatabase->readValues("SELECT customOptionVariantID FROM " . DB_PREFIX . "product_custom_option_variant WHERE customOptionID =" . $option_id . $condition);
            if (!empty($deleted_variants)) {
                foreach ($deleted_variants as $v_id) {
                    $deleted_variant[] = $v_id['customOptionVariantID'];
                }
                $deleted_variant_str = implode("','", $deleted_variant);
            }
            if (!empty($deleted_variants)) {
                //echo "DELETE FROM ".DB_PREFIX."product_custom_option_variant WHERE customOptionVariantID IN ('".$deleted_variant_str."')";
                $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_custom_option_variant WHERE customOptionVariantID IN ('" . $deleted_variant_str . "')");
                $this->ObjDatabase->setQuery("DELETE FROM " . DB_PREFIX . "product_custom_option_variant_details WHERE customOptionVariantID IN ('" . $deleted_variant_str . "')");
                foreach ($deleted_variants as $v_id) {
                    //fn_delete_image_pairs($v_id, 'variant_image');
                }
            }
        }
        if ($option_id) {
            $glob_link = array(
                'customOptionID' => $option_id,
                'productID' => $product_id
            );
            $this->ObjDatabase->setQuery("REPLACE INTO " . DB_PREFIX . "product_custom_option_link" . $this->insert($glob_link));
        }
        // Rebuild exceptions
        /*if (!empty($create) && !empty($option_data['product_id'])) {
        fn_update_exceptions($option_data['product_id']);
        }*/
        /**
         * Update product option (running after fn_update_product_option() function)
         *
         * @param array $option_data Array with option data
         * @param int $option_id Option identifier
         * @param array $deleted_variants Array with deleted variants ids
         * @param string $lang_code Language code to add/update option for
         */
        return $option_id;
    }
    function fn_exim_set_product_main_import_images($images_path, $thumb, $product_id, $main) {
        if (!empty($product_id)) {
            if ((!empty($main)) && ((strpos($main, '/') == false)))
                $params['import_main_image'] = $images_path . "/" . $main;
            if ((!empty($thumb)) && ((strpos($thumb, '/') == false)))
                $params['import_preview_image'] = $images_path . "/" . $thumb;
            $where['productID'] = $product_id;
            if (!empty($params)) {
                $queryUpdate = $this->update($params, $where);
                $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET " . $queryUpdate['cond'] . " WHERE " . $queryUpdate['where']);
            }
            return true;
        } else
            return false;
    }
    function fn_exim_set_product_image($images_path, $thumb, $product_id, $main) {
        $objProduct = new ProductModel();
        $ObjImage   = new ImageModel();
        $imageFlag  = 0;
        if (!empty($product_id)) {
            
            //get previous image
            $sql    = "
			SELECT 
				productImage,productLock
			FROM 
					" . DB_PREFIX . "products 
				WHERE  productID='".$product_id."' ";
        $resImage = $this->ObjDatabase->readValue($sql);
            $prevImage = $resImage['productImage'];
            if (!empty($main)) {
                $main                           = trim($main);
                $dataResize['previewHeight']    = $this->getSettings('preview_height');
                $dataResize['previewWidth']     = $this->getSettings('preview_width');
                $dataResize['thumbHeight']      = $this->getSettings('thumb_height');
                $dataResize['thumbWidth']       = $this->getSettings('thumb_width');
                $dataResize['smallthumbWidth']  = $this->getSettings('small_thumb_width');
                $dataResize['smallthumbHeight'] = $this->getSettings('small_thumb_height');
                if (strpos($thumb, '/') !== false && strpos($main, '/') !== false)
                    $imageFlag = 1;
                if ($imageFlag != 1) {
                    //thumb exist
                    if (strpos($thumb, '/') !== false)
                        $MediaArry['thumbImage_temp'] = '';
                    //thumb changes
                    elseif ($thumb != '')
                        $MediaArry['thumbImage_temp'] = $images_path . "/" . $thumb;
                    //thumb null
                    else
                        $MediaArry['thumbImage_temp'] = '';
                    //@Main Image change sections//
                    //main exist
                    if (strpos($main, '/') !== false) {
                        $Image                       = $objProduct->getImageName($main);
                        $MediaArry['mainImage_temp'] = "";
                    }
                    //main changes
                    else {
                        $Image                       = substr_replace($main, "_" . rand(1, 1000) . '.', strrpos($main, '.'), 1);
                        $MediaArry['mainImage_temp'] = $images_path . "/" . $main;
                        //main changes : preview same
                        if (strpos($thumb, '/') !== false) {
                            $MediaArry['thumbFlag'] = 1;
                            $MediaArry['resImage']  = $thumb;
                        }
                    }
                    $MediaArry['mediaParam'] = $dataResize;
                    $MediaArry['destFolder'] = 'product';
                    $MediaArry['mainImage']  = $Image;
                    $MediaArry['productID']  = $product_id;
                    //echo $MediaArry['mainImage_temp'];
                    //echo $MediaArry['thumbImage_temp'];
                    $main_fullpath           = __ROOT_PATH . '/' . $MediaArry['mainImage_temp'];
                    if (is_file($main_fullpath) && file_exists($main_fullpath)) {
                        $upload_flag = 0;
                        if ($MediaArry['thumbImage_temp'] != '') {
                            $thumb_fullpath = __ROOT_PATH . '/' . $MediaArry['thumbImage_temp'];
                            if (!(file_exists($thumb_fullpath)))
                                $upload_flag = 1;
                        }
                    } else {
                        $upload_flag = 1;
                    }
                    if ($upload_flag != 1) {
                        $upload_images      = $this->getSettingValue('site_settings', 'upload_images_to');
                        if ($upload_images == 'filesystem') {
                                    $objProduct->unlinkImages($prevImage, 'product');}
                        else{
                                    $ObjImage->unlinkAWSImage($prevImage, 'product');
                        }	
                        $image = $objProduct->generateMedia($MediaArry);
                       
                        if($resImage['productLock']=="No")		
                            $exeSucc = $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET productImage='" . $image . "',productStatus='Active', import_main_image ='' , import_preview_image='' WHERE productID='" . $product_id . "'");
                        else
                            $exeSucc = $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET productImage='" . $image . "', import_main_image ='' , import_preview_image='' WHERE productID='" . $product_id . "'");
                    }else{
                        return false;
                    }
                }
                return true;
            } else
                return false;
        } else
            return false;
    }
    function fn_exim_set_import_image($images_path, $thumb, $object_id, $main, $sku, $type, $businessID = '') {
        $objProduct = new ProductModel();
        $imageFlag  = 0;
        $flag       = 0;
        $product_id = $this->fn_exim_get_product_id($sku, $type, $businessID);
        if (($type != 'C' && $type != 'DO') || empty($sku))
            return false;
        if (empty($object_id)) {
            if ($type == 'DO') {
                $result    = $this->ObjDatabase->readValue("SELECT productOptionID FROM " . DB_PREFIX . "product_options DO
								INNER JOIN " . DB_PREFIX . "products D ON(D.productID=DO.productID) WHERE D.businessID=" . $businessID . " AND DO.optionSKU ='" . $this->fn_html_entity_encode($sku) . "'
                                                                AND DO.productOptionStatus != 'Delete' ");
                $object_id = $result['productOptionID'];
            } else {
                $result    = $this->ObjDatabase->readValue("SELECT combinationID FROM " . DB_PREFIX . "product_combination PCO
								INNER JOIN " . DB_PREFIX . "products D ON(D.productID=PCO.productID) WHERE PCO.status!='D' AND D.businessID=" . $businessID . " AND  combinationSKU ='" . $sku . "'");
                $object_id = $result['combinationID'];
            }
        }
        
        if (!empty($object_id)) {
            $isexist_media = $this->ObjDatabase->readValue("SELECT productMediaID FROM " . DB_PREFIX . "product_media WHERE productMedia ='" . $main . "' AND  productObjectType='" . $type . "' AND productObjectID='" . $object_id . "'");
            $media         = $isexist_media['productMediaID'];
            if (empty($media) && (strpos($thumb, '/') !== false)) {
                $isexist_media = $this->ObjDatabase->readValue("SELECT productMediaID FROM " . DB_PREFIX . "product_media WHERE productMedia ='" . $thumb . "' AND  productObjectType='" . $type . "' AND productObjectID='" . $object_id . "'");
                $media         = $isexist_media['productMediaID'];
                $flag          = 1;
            }
            if ($main != '') {
                if ($type == 'DO')
                    $MediaArry['destFolder'] = 'product';
                else {
                    $MediaArry['destFolder'] = 'product-combination';
                    //$this->ObjDatabase->setQuery("DELETE FROM ".DB_PREFIX."product_media WHERE  productObjectType='C' AND productObjectID='".$object_id."'");
                }
                $dataResize['previewHeight']    = $this->getSettings('preview_height');
                $dataResize['previewWidth']     = $this->getSettings('preview_width');
                $dataResize['thumbHeight']      = $this->getSettings('thumb_height');
                $dataResize['thumbWidth']       = $this->getSettings('thumb_width');
                $dataResize['smallthumbWidth']  = $this->getSettings('small_thumb_width');
                $dataResize['smallthumbHeight'] = $this->getSettings('small_thumb_height');
                if ((strpos($thumb, '/') !== false && strpos($main, '/') !== false) || ($thumb == "" && strpos($main, '/') !== false))
                    $imageFlag = 1;
                if ($imageFlag != 1) {
                    //thumb exist
                    if (strpos($thumb, '/') !== false)
                        $MediaArry['thumbImage_temp'] = '';
                    //thumb changes
                    elseif ($thumb != '')
                        $MediaArry['thumbImage_temp'] = $images_path . "/" . $thumb;
                    //thumb null
                    else
                        $MediaArry['thumbImage_temp'] = '';
                    //@Main Image change sections//
                    //main exist
                    if (strpos($main, '/') !== false) {
                        $Image                       = $objProduct->getImageName($main);
                        $MediaArry['mainImage_temp'] = "";
                    }
                    //main changes
                    else {
                        $Image                       = substr_replace($main, "__" . rand() . '.', strrpos($main, '.'), 1);
                        $MediaArry['mainImage_temp'] = $images_path . "/" . $main;
                        //main changes : preview same
                        if (strpos($thumb, '/') !== false) {
                            $MediaArry['thumbFlag'] = 1;
                            $MediaArry['resImage']  = $thumb;
                        }
                    }
                    $MediaArry['mediaParam'] = $dataResize;
                    $MediaArry['mainImage']  = $Image;
                    $MediaArry['productID']  = $product_id;
                    //echo "<pre>";print_r($MediaArry);exit;
                    $image                   = $objProduct->generateMedia($MediaArry);
                    if(file_exists($images_path . "/" . $main))
                    {
                        if (empty($media)) {
                        $savecomboimge = "INSERT INTO `" . DB_PREFIX . "product_media`(
										`productID`,
										`productObjectID`,
										`productMedia`,
										`productObjectType`,
										`productMediaType`,
										`productMediaStatus`
								)
								VALUES
								(
								'" . $product_id . "',
								'" . $object_id . "',
								'" . $image . "',
								'" . $type . "',
								'I',
								'A'
								)";
                        $this->ObjDatabase->setQuery($savecomboimge);
                        $this->import_db_skip_new++;
                        } else {
                            if ($flag == 1)
                                $this->ObjDatabase->setQuery("UPDATE `" . DB_PREFIX . "product_media` SET `productMedia`='" . $image . "' WHERE  productMediaID='" . $media . "'");
                            $this->import_db_skip_exist++;
                        }
                    }
                } else
                    $this->import_db_skip_exist++;
                return true;
            }
            return true;
        } else
            return false;
    }
    function generate_random_unique($length) {
        $random = '';
        for ($i = 0; $i < $length; $i++) {
            $random .= rand(0, 1) ? rand(0, 9) : chr(rand(ord('a'), ord('z')));
        }
        return $random;
    }
    //FETCH SETTINGS BY SETTINGS KEY
    public function getSettings($settingsKey) {
        $sql    = "SELECT
								settingsValue
							FROM
								" . DB_PREFIX . "settings
							WHERE
								settingsKey='" . $settingsKey . "'";
        $result = $this->ObjDatabase->readValue($sql);
        return $result['settingsValue'];
    }
    function fn_exim_get_box_size($product_id) {
        $sql             = "
			SELECT 
				packageWeight,
				packageLength,
				packageWidth,
				packageHeight 
			FROM 
				" . DB_PREFIX . "product_options 
			WHERE 
				productOptionDefault='Yes' 
				AND 
				productID ='" . $product_id . "'";
        $shipping_params = $this->ObjDatabase->readValue($sql, MYSQLI_ASSOC);
        if (!empty($shipping_params)) {
            return 'length:' . (empty($shipping_params['packageLength']) ? 0 : $shipping_params['packageLength']) . ';width:' . (empty($shipping_params['packageWidth']) ? 0 : $shipping_params['packageWidth']) . ';height:' . (empty($shipping_params['packageHeight']) ? 0 : $shipping_params['packageHeight']) . ';weight:' . (empty($shipping_params['packageWeight']) ? 0 : $shipping_params['packageWeight']);
        }
        return 'length:0;width:0;height:0';
    }
    function fn_exim_put_box_size($product_id, $data, $sku, $product_name) {
        $ObjLanguage                            = new LanguageModel();
        $resLanguages                           = $ObjLanguage->listLanguages("", "Active");
        if (empty($data)) {
            return false;
        }
        $length = $width = $height = 0;
        $params = explode(';', $data);
        foreach ($params as $param) {
            $elm = explode(':', $param);
            if ($elm[0] == 'length') {
                $length = floatval($elm[1]);
            } elseif ($elm[0] == 'width') {
                $width = floatval($elm[1]);
            } elseif ($elm[0] == 'height') {
                $height = floatval($elm[1]);
            } elseif ($elm[0] == 'weight') {
                $weight = floatval($elm[1]);
            }
        }
        $shipping_params['packageLength'] = $length;
        $shipping_params['packageWidth']  = $width;
        $shipping_params['packageHeight'] = $height;
        $shipping_params['packageWeight'] = $weight;
        $where['productID']               = $product_id;
        $where['productOptionDefault']    = 'Yes';
        $queryUpdate                      = $this->update($shipping_params, $where);
        $is_exists                        = $this->ObjDatabase->getField("SELECT COUNT(1) FROM " . DB_PREFIX . "product_options WHERE productOptionDefault='Yes' AND productID ='" . $product_id . "'");
        if ($is_exists == true) {
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "product_options SET " . $queryUpdate['cond'] . " WHERE " . $queryUpdate['where']);
        } else {
            $shipping_params['productID']            = $product_id;
            $shipping_params['productOptionDefault'] = 'Yes';
            $shipping_params['optionSKU']            = $sku;
            $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_options" . $this->insert($shipping_params));
            $option_detail_data['productOptionID']   = $option_id = $this->ObjDatabase->getInsertId();
            $option_detail_data['productOptionName'] = $product_name;
            foreach ($resLanguages as $key => $_v) {
                $option_detail_data['languageID'] = $_v['languageID'];
                $this->ObjDatabase->setQuery("INSERT INTO " . DB_PREFIX . "product_option_details" . $this->insert($option_detail_data));
            }
        }
        return true;
    }
    function fn_html_entity_encode($data) {
        if (!is_array($data)) {
            $data = htmlspecialchars($data, ENT_NOQUOTES, 'UTF-8');
            return $this->escape($data);
        } else {
            return $data;
        }
    }
    // Import preprocessor
    function fn_exim_reset_extra($insert_ids, $productType, $timezone, $currency, $status) {
        $ObjProduct = new ProductModel();
        if (!empty($insert_ids)) {
            foreach ($insert_ids as $productID) {
                $ObjProduct->assignDefaultSmService($productID);
            }
            $insert_ids = implode("','", $insert_ids);
			if($status =='Pending'){
            $this->ObjDatabase->setQuery("UPDATE `" . DB_PREFIX . "products` SET `productCreatedDate`=NOW(),`productTimeZone` ='" . $timezone . "',`productTypeID`='" . $productType . "',`productDefaultCurrency`='" . $currency . "',`productStatus`='" . $status . "'  WHERE productID IN ('" . $insert_ids . "')");
			}
			else
			{
            $this->ObjDatabase->setQuery("UPDATE `" . DB_PREFIX . "products` SET `productCreatedDate`=NOW(),`productTimeZone` ='" . $timezone . "',`productTypeID`='" . $productType . "',`productDefaultCurrency`='" . $currency . "'  WHERE productID IN ('" . $insert_ids . "')");
			}
        }
    }
    function fn_array_merge() {
        $arg_list      = func_get_args();
        $preserve_keys = true;
        $result        = array();
        if (is_bool(end($arg_list))) {
            $preserve_keys = array_pop($arg_list);
        }
        foreach ((array) $arg_list as $arg) {
            foreach ((array) $arg as $k => $v) {
                if ($preserve_keys == true) {
                    $result[$k] = !empty($result[$k]) && is_array($result[$k]) ? $this->fn_array_merge($result[$k], $v) : $v;
                } else {
                    $result[] = $v;
                }
            }
        }
        return $result;
    }
    /* API function */
    private function output($data, $responseType) {
        switch ($responseType) {
            case 'json':
                echo json_encode($data);
                exit;
            case 'xml':
                $error = array(
                    'response' => 'Not Found',
                    'responseCode' => 404,
                    'message' => 'No Service Found, May be available in future'
                );
                echo json_encode($error);
                exit;
            case 'array':
                return $data;
        }
    }
    /*
     * Make a string lowercase
     *
     * @param string $string - the string being lowercased
     * @param string $charset - charset being used 
     * @return string
     */
    function fn_strtolower($string, $charset = CHARSET) {
        if (function_exists('mb_strtolower')) {
            return strtolower($string);
        } else {
            return strtolower($string);
        }
    }
    function fn_exim_get_key($key) {
        return $key;
    }
    function fn_exim_get_product_id($sku, $type, $businessID = '') {
        if ($type == 'DO') {
            $result = $this->ObjDatabase->readValue("SELECT DO.productID FROM " . DB_PREFIX . "product_options DO
								INNER JOIN " . DB_PREFIX . "products D ON(DO.productID=D.productID) WHERE DO.productOptionStatus!='Delete' AND D.businessID=" . $businessID . " AND optionSKU ='" . $sku . "'");
            return $object_id = $result['productID'];
        } else {
            $result = $this->ObjDatabase->readValue("SELECT pco.productID FROM " . DB_PREFIX . "product_combination pco LEFT JOIN " . DB_PREFIX . "products d ON(d.productID=pco.productID) WHERE pco.status!='D' AND d.businessID=" . $businessID . " AND combinationSKU ='" . $sku . "'");
            return $object_id = $result['productID'];
        }
    }
    function fn_size_id_to_unit($size_id) {
        return $class = $this->ObjDatabase->getField("SELECT class FROM " . DB_PREFIX . "measurement_class WHERE classID ='" . trim($size_id) . "'");
    }
    function fn_unit_to_size($size) {
        return $classID = $this->ObjDatabase->getField("SELECT classID FROM " . DB_PREFIX . "measurement_class WHERE class ='" . trim($size) . "'");
    }
    //Brand
    function fn_brand_id_to_name($brand_id) {
        return $this->ObjDatabase->getField("SELECT  brandName FROM " . DB_PREFIX . "brand_details WHERE languageID='1' AND brandID ='" . trim($brand_id) . "'");
    }
    function fn_brand_name_to_id($key) {
        return $brandID = $this->ObjDatabase->getField("SELECT brandDet.brandID FROM " . DB_PREFIX . "brand_details brandDet
								LEFT JOIN 
			" . DB_PREFIX . "brands brand ON(brand.brandID=brandDet.brandID)				   
												   WHERE brandDet.languageID='1' AND brandDet.brandName ='" . trim($key) . "'");
    }
    //Dispatch
    function fn_dispatch_id_to_time($id) {
        $brandKey = $this->ObjDatabase->getField("SELECT  dispatchTime FROM " . DB_PREFIX . "product_dispatched_in_days WHERE dispatchID ='" . trim($id) . "'");
        if (!empty($brandKey))
            return "[" . $brandKey . "]";
        else
            return "";
    }
    function fn_time_to_dispatch_id($time) {
        if (!empty($time)) {
            $time = trim($time, '[]');
            return $brandID = $this->ObjDatabase->getField("SELECT dispatchID FROM " . DB_PREFIX . "product_dispatched_in_days WHERE dispatchTime ='" . trim($time) . "'");
        } else
            return "";
    }
    function fn_get_preview($thumb) {
        if (!empty($thumb))
            return $thumb = trim($thumb);
        else
            return "";
    }
    /* function to add all errors */
    private function reportError($err) {
        extract($err);
        if ($errType == 'filterKey') {
            $this->errors[] = array(
                "errorFrom" => "filter key",
                "errorField" => $error,
                "errorMsg" => "Un-expected filter key (" . $error . ")"
            );
        } else if ($errType == 'order') {
            $this->errors[] = array(
                "errorFrom" => "order by",
                "errorField" => $error,
                "errorMsg" => "Un-expected order by field (" . $error . ")"
            );
        } else if ($errType == 'dir') {
            $this->errors[] = array(
                "errorFrom" => "order by - Dir",
                "errorField" => $error,
                "errorMsg" => "Wrong parameter '" . $error . "'. ASC or DESC Expected"
            );
        } else if ($errType == 'no write-permission') {
            $this->errors[] = array(
                "errorFrom" => "no write-permission",
                "errorField" => $error,
                "errorMsg" => $errorMessage
            );
        } else if ($errType == 'input_data') {
            $this->errors[] = array(
                "errorFrom" => "Input Data",
                "errorMsg" => $errorMessage
            );
        } else if ($errType == 'record_exists') {
            $this->errors[] = array(
                "errorFrom" => $error,
                "errorMsg" => $errorMessage
            );
        } else if ($errType == 'resource_restricted') {
            $this->errors[] = array(
                "status" => '403',
                "errorMsg" => 'Permission denied'
            );
        } else {
            $this->errors[] = array(
                "errorFrom" => "required:" . $error,
                "errorField" => $error,
                "errorMsg" => $errorMessage,
                "record" => $record
            );
        }
        return true;
    }
    public function fn_put_checkExists($data, $table, $field, $query, $pkField = '', $pkValue = '') {
        if ($pkField != '') {
            $query .= " AND " . $pkField . " !='" . $pkValue . "'";
        }
        if ($this->ObjDatabase->checkExist($table, $field, $data, $query) == 'YES') {
            $errorArray = array(
                'error' => $field,
                'errType' => 'record_exists',
                'errorMessage' => "Data Already exists(" . $field . ":" . $data . ")"
            );
            $this->reportError($errorArray);
        } else {
            return $data;
        }
    }
    public function fn_exim_get_image($pid) {
        $file = $this->ObjDatabase->getField("SELECT productImage FROM " . DB_PREFIX . "products WHERE productID ='" . trim($pid) . "'");
        if (!empty($file))
            return $file;
        else
            return "";
    }
    public function fn_exim_get_main_image($pid) {
        $file = $this->ObjDatabase->getField("SELECT productImage FROM " . DB_PREFIX . "products WHERE productID ='" . trim($pid) . "'");
        if (!empty($file))
            return $file;
        else
            return "";
    }
    public function fn_exim_get_mimage($file, $type) {
        if ($type == 'DO')
            $destination = "product";
        else
            $destination = "product-combination";
        $fileName = __CORE_PUBLIC_PATH . "/uploads/catalog/" . $destination . "/preview-main/" . $file;
        if (file_exists($fileName))
            return $file;
        else
            return "";
    }
    /* function to check if there is any errors */
    private function hasError() {
        if (empty($this->errors)) {
            return false;
        } else {
            return true;
        }
    }
    /* function to return errors */
    private function getErrors() {
        return $this->errors;
    }
    private function showErrors() {
        $error           = array(
            'status' => 'Failure'
        );
        $error['errors'] = $this->getErrors();
        echo json_encode($error);
        exit;
    }
    private function setUpdatedKeys($keys) {
        $this->updatedKeys[] = $keys;
    }
    private function getUpdatedKeys() {
        return $this->updatedKeys;
    }
    private function setInsertedKeys($keys) {
        $this->insertedKeys[] = $keys;
    }
    private function getInsertedKeys() {
        return $this->insertedKeys;
    }
    /* function to set generate productUrl */
    private function fn_generate_productUrl($productName) {
        $string = str_replace(" ", "-", trim($productName)); // Replaces all spaces with hyphens.
        $string = preg_replace('/[^A-Za-z0-9\-]/', '-', $string); // Removes special chars.
        $string = preg_replace('/-+/', '-', $string); // Removes continuous hypens with a single hypen.
        return strtolower($string);
    }
    /* function to insert or update product and store details to rewrite table */
    function fn_insert_basic_rewrite_details($productID, $productUrl, $category = 0) {
        //URL Rewrite 							
        $ObjLanguage = new LanguageModel();
        $langsList   = $ObjLanguage->listLanguages();
        foreach ($langsList as $lang) {
            $languageIDs[] = $lang['languageID'];
        }
        $args      = array(
            'productUrl' => $productUrl
        );
        $urlSuffix = $this->getSettings('product_url_suffix');
        $product_sef_format = $this->getSettings( 'product_sef_format');
        $product_sef_format=    isset($product_sef_format)  ? $product_sef_format   : false;
        $SefModel  = new SefModel();
        if ($category && $product_sef_format)
            $args['category'] = $category;
        $SefModel->_refreshProductRewrites($languageIDs, $productID, $urlSuffix, $args,'',$product_sef_format);
    }
    function fn_clean_productUrl($productUrl) {
        if (!empty($productUrl)) {
            $productUrl = html_entity_decode($productUrl);
            return $productUrl = $this->fn_generate_productUrl($productUrl);
        } else
            return "";
    }
    function fn_exim_get_shipping_origin($key, $businessID) {
        $values   = $this->ObjDatabase->readValue("SELECT shippingOrigin,shippingSetting FROM " . DB_PREFIX . "products WHERE productID ='" . trim($key) . "'");
        $origin   = $values['shippingOrigin'];
        $manageby = $values['shippingSetting'];
        if ($origin == '0' && $manageby == 'admin') {
            return "Global";
        } else {
            if ((!empty($origin)) && $origin > 0)
                return $this->ObjDatabase->getField("SELECT  buslocDet.locName FROM " . DB_PREFIX . "business_location_details buslocDet LEFT JOIN 
			" . DB_PREFIX . "business_locations busLoc ON(buslocDet.businessLocID=busLoc.businessLocID) WHERE businessID='" . $businessID . "' AND buslocDet.businessLocID ='" . $origin . "' AND 
			languageID = 1 LIMIT 1");
            else
                return "";
        }
    }
    function fn_exim_set_shipping_origin($product_id, $origin, $businessID) {
        if (!empty($origin)) {
            if ($origin == 'Global')
                $ship_origin = "0";
            else {
                $ship_origin = $this->ObjDatabase->getField("SELECT  buslocDet.businessLocID FROM " . DB_PREFIX . "business_location_details buslocDet LEFT JOIN 
			" . DB_PREFIX . "business_locations busLoc ON(buslocDet.businessLocID=busLoc.businessLocID) WHERE busLoc.businessID='" . $businessID . "' AND buslocDet.locName ='" . $origin . "' AND 
			languageID = 1 LIMIT 1");
                if (empty($ship_origin))
                    $ship_origin = 'NULL';
            }
            $this->ObjDatabase->setQuery("UPDATE `" . DB_PREFIX . "products` SET `shippingOrigin` ='" . $ship_origin . "' WHERE productID ='" . $product_id . "'");
        }
    }
    // Export product shipping
    // Parameters:
    // @product_id - product ID
    // @lang_code - language code
    function fn_exim_get_product_shipping($product_id, $lang_code = '') {
        $pair_delimiter         = ':';
        $set_delimiter          = ';';
        $languageIDs['Current'] = $lang_code;
        $result                 = array();
        $ObjProduct             = new ProductModel();
        $options                = $ObjProduct->getProductShippings($product_id, $languageIDs);
        $parent                 = '';
        foreach ($options as $o) {
            $zone     = (!empty($o['zone'])) ? str_replace(',', '/', $o['zone']) : '';
            $parent   = '(' . $this->fn_html_entity_decode($o['SMservice']) . ') ';
            $tax      = $this->fn_exim_get_taxes($o['taxClassID']);
            $result[] = $this->fn_exim_post_item_id($o['shippingtoproductID']) . $parent . "[DZ(" . $zone . '),BC(' . $o['baseCharge'] . '),MQ(' . $o['maxQtyPerShipping'] . '),EC(' . $o['chargePerExtraQty'] . '),HC(' . $o['handlingCharge'] . '),TX(' . $tax . ')]';
        }
        return !empty($result) ? implode($set_delimiter, $result) : '';
    }
    function fn_exim_set_product_shipping($product_id, $data, $lang_code = '') {
        $pair_delimiter = '[';
        $set_delimiter  = ';';
        $vars_delimiter = ',';
        if ((!empty($data))) {
            $options = explode($set_delimiter, $data);
            if (!empty($options)) {
                $updated_ids = array(); // store updated ids, delete other (if exist)
                $o_position  = 0;
                foreach ($options as $option) {
                    if (!empty($option)) {
                        $pair     = explode($pair_delimiter, $option);
                        $variants = '';
                        if (is_array($pair)) {
                            array_walk($pair, array(
                                $this,
                                'fn_trim_helper'
                            ));
                            $pair[1] = '[' . $pair[1];
                            if (($pos = strpos($pair[1], '[')) !== false) { // option has variants
                                $variants = substr($pair[1], $pos + 1, strlen($pair[1]) - $pos - 2);
                                $variants = explode($vars_delimiter, $variants);
                            }
                            $shipping_id   = $this->fn_exim_get_item_id($pair[0]);
                            $shipping_name = $this->fn_exim_get_item_name($pair[0]);
                            $_restore      = false;
                            if (!empty($shipping_id)) {
                                $result = $this->ObjDatabase->readValue("SELECT shippingtoproductID
																 FROM " . DB_PREFIX . "shipping_to_product
																 WHERE shippingtoproductID ='" . $shipping_id . "'");
                                if ($result['shippingtoproductID'])
                                    $_restore = true;
                            }
                            // Generate array for variants
                            $v_data     = array();
                            $v_data_ids = array();
                            if (!empty($variants) && is_array($variants)) {
                                $position = 0;
                                foreach ($variants as $v) {
                                    $position += 10;
                                    $v_data[] = array(
                                        'variant_name' => $v,
                                        'position' => $position
                                    );
                                }
                            }
                            $shipping_data = array(
                                'option_name' => $shipping_name,
                                'variants' => $v_data
                            );
                            // Option doesn't exist, create new					
                            if (empty($shipping_id)) {
                                $shipping_data['product_id'] = $product_id;
                                $updated_ids[]               = $this->fn_update_product_shipping($shipping_data, 0, $lang_code);
                                // Option is exist, update it
                            } else {
                                $option_data['product_id'] = $product_id;
                                $updated_ids[]             = $this->fn_update_product_shipping($shipping_data, $shipping_id, $lang_code);
                            }
                        }
                    }
                }
                // Delete all other options
                if (!empty($updated_ids)) {
                    $updated_ids  = implode(',', $updated_ids);
                    $sql          = "
						SELECT  
							shippingtoproductID 
						FROM 
							" . DB_PREFIX . "shipping_to_product 
						WHERE 
							shippingtoproductID NOT IN (" . $updated_ids . ") 
							AND 
							productID =" . $product_id;
                    $obsolete_ids = $this->ObjDatabase->readValues($sql);
                    if (!empty($obsolete_ids)) {
                        foreach ($obsolete_ids as $o_id) {
                            $this->fn_delete_product_shipping($o_id['shippingtoproductID'], $product_id);
                        }
                    }
                }
            }
        }
        return true;
    }
    //Brands
    private function fn_create_key($str, $brandID) {
        $urlKey = preg_replace('/[_|~`!#$^&*()={}[\]\'?+ ><]+/', '-', $str);
        $urlKey = preg_replace('/\s+/', '_', $urlKey);
        $urlKey = strtolower($urlKey);
        $urlKey = trim($urlKey, '-');
        $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "brands
									SET brandKey='" . $urlKey . "' WHERE brandID='" . $brandID . "'");
    }
    private function fn_exim_set_brand_image($images_path, $brandID, $brandIcon) {
        $ObjProduct = new ProductModel();
        $ObjImage   = new ImageModel();
        if (!empty($brandIcon)) {
            $main_path               = $images_path . "/" . $brandIcon;
            $brandKey                = $brandIcon;
            $brandIcon               = strtolower($brandIcon[0]) . "/" . strtolower($brandIcon[1]) . "/" . $brandIcon;
            $brand_icon_width        = $this->getSettings('brand_icon_width');
            $brand_icon_height       = $this->getSettings('brand_icon_height');
            $brand_icon_thumb_width  = $this->getSettings('brand_icon_thumb_width');
            $brand_icon_thumb_height = $this->getSettings('brand_icon_thumb_height');
            $enable_cdn              = $this->getSettings('enable_cdn_images');
            $mainDir                 = __CORE_PUBLIC_UPLOADS_PATH . "brand/";
            if ($enable_cdn != 'Yes') {
                $fullBrandIconImageSmallLevel1 = $mainDir . "small/" . strtolower($brandKey[0]) . "/";
                $fullBrandIconImageSmallLevel2 = $fullBrandIconImageSmallLevel1 . strtolower($brandKey[1]) . "/";
                $fullBrandIconImageThumbLevel1 = $mainDir . "thumb/" . strtolower($brandKey[0]) . "/";
                $fullBrandIconImageThumbLevel2 = $fullBrandIconImageThumbLevel1 . strtolower($brandKey[1]) . "/";
                if (!is_dir($fullBrandIconImageSmallLevel1)) {
                    mkdir($fullBrandIconImageSmallLevel1, 0777);
                    mkdir($fullBrandIconImageThumbLevel1, 0777);
                }
                if (!is_dir($fullBrandIconImageSmallLevel2)) {
                    mkdir($fullBrandIconImageSmallLevel2, 0777);
                    mkdir($fullBrandIconImageThumbLevel2, 0777);
                }
            }
            $target_path = $ObjProduct->getDestFilePath($main_path);
            $ObjImage->resizeImage(__ROOT_PATH . '/' . $main_path, $target_path, $brand_icon_width, $brand_icon_height);
            $ObjImage->copy_file($target_path, '/' . __UPLOADS_FOLDER . 'brand/small/' . $brandIcon);
            $ObjImage->resizeImage(__ROOT_PATH . '/' . $main_path, $target_path, $brand_icon_thumb_width, $brand_icon_thumb_height);
            $ObjImage->copy_file($target_path, '/' . __UPLOADS_FOLDER . 'brand/thumb/' . $brandIcon);
            @unlink($target_path);
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "brands SET brandIcon='" . $brandIcon . "' WHERE brandID='" . $brandID . "'");
        }
        return true;
    }
    function fn_exim_get_taxClassID($product_id) {
        return $this->ObjDatabase->getField("SELECT taxClassID FROM " . DB_PREFIX . "products WHERE productID ='" . trim($product_id) . "'");
    }
    function fn_exim_set_taxClassID($product_id, $taxclassID) {
        if ($taxclassID != '') {
            if ($taxclassID > 0)
                $isTaxable = 'Yes';
            else
                $isTaxable = 'No';
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "products SET taxClassID='" . $taxclassID . "',isTaxable='" . $isTaxable . "' WHERE productID='" . $product_id . "'");
        }
        return true;
    }
    function fn_insert_images_cron($folderName='') {
        $sql    = "
			SELECT 
				import_main_image,
				import_preview_image,
				productID
			FROM 
					" . DB_PREFIX . "products 
				WHERE  (import_main_image !='' OR import_preview_image!='' ) ";
        if($folderName!='')
            $sql .= " AND import_main_image LIKE 'public/uploads/exim/".$folderName."/%' ";
         $sql.=    " ORDER BY productID asc LIMIT 100 ";
       
        $result = $this->ObjDatabase->readValues($sql, MYSQLI_ASSOC);
        $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "cron_insert_images
									SET status='locked'");
        
        //get all records
        $allsql    = "
			SELECT 
				productID
			FROM 
					" . DB_PREFIX . "products ";
       $allsql  .= "	WHERE  (import_main_image !='' OR import_preview_image!='')  ";
        if($folderName!='')
            $allsql .= " AND import_main_image LIKE 'public/uploads/exim/".$folderName."/%' ";
        $allResult = $this->ObjDatabase->readValues($allsql, MYSQLI_ASSOC);
		//echo $allsql;exit;
        $totalRecords = count($allResult);
        $processedCount = 0;
        if (count($result) > 0) {
            foreach ($result as $key => $image) {
                $productID = $image['productID'];
                //$sqlGet     =   "select optionSKU from dp_product_options where productID='".$productID."' AND productOptionStatus!='Delete' LIMIT 0,1";                    
                //$resGet     =   $this->ObjDatabase->readValue($sqlGet);
                //echo $productID;exit;
                if (!empty($image['import_main_image'])) {
                    
                    //$image['import_main_image'] = str_replace('FAlAc','FalAc',$image['import_main_image']);
                    //$image['import_main_image'] = str_replace('_','-',$image['import_main_image']);
                    /*$sp = explode("/",$image['import_main_image']);
                    $img  =  explode(".",$sp[5]);
                    
                   $image['import_main_image'] = $img[0]."-1".".".$img[1];
                  
                   if(substr($img[0],0,5)=='Sarac') {
                       $img[0] = str_replace('Sarac','SarAc',$img[0]);
                   }
                   $image['import_main_image'] = $img[0]."-1".".".$img[1];
                    */
                    //ISTlA
                    $mainImage   = pathinfo($image['import_main_image']);
                    $images_path = $mainImage['dirname'];
                    $main        = $mainImage['basename'];
                    if (!empty($image['import_preview_image'])) {
                        $thumbImage = pathinfo($image['import_preview_image']);
                        $thumb      = $thumbImage['basename'];
                    } else
                        $thumb = '';
                  
                    $resProcess = $this->fn_exim_set_product_image($images_path, $thumb, $productID, $main);
                    if($resProcess)
                    {$processedCount++;} else {
						//echo $productID." ".$image['import_main_image']."<br>";
					}
                }
            }
            $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "cron_insert_images
										SET status='active'");
            
            echo $processedCount." records has been processed successfully. ".($totalRecords-$processedCount)." record updates are pending";
            if($processedCount==0 && $totalRecords>0)
                echo "<br/>Please check if the Images are uploaded to the correct folder path";
            exit;
        } else {
            echo "no products";
            exit;
        }
    }
    function fn_get_image_cron_status() {
        $result = $this->ObjDatabase->readValue("SELECT 
													status,last_executed_date
													FROM 
													" . DB_PREFIX . "cron_insert_images LIMIT 1", MYSQLI_ASSOC);
        $status = $result['status'];
        if ($status == 'locked') {
            $to_time   = strtotime(date('Y-m-d H:i:s'));
            $from_time = strtotime($result['last_executed_date']);
            if (round(abs($to_time - $from_time) / 60, 2) > 10)
                $this->ObjDatabase->setQuery("UPDATE " . DB_PREFIX . "cron_insert_images
										SET status='active'");
            $status = 'active';
        }
        return $status;
    }
    function fn_exim_get_product_categories($product_id, $lang_code = '') {
        $languageIDs['Current'] = $languageIDs['Default'] = $lang_code;
        $ObjProduct             = new ProductModel();
        $resProductcategory     = $this->listProductTocategoryDetails($languageIDs, $product_id, "All");
        $set_delimiter          = ';';
        $item_delimiter         = '///';
        $result                 = array();
        foreach ($resProductcategory as $category) {
            $parent            = '';
            $parent_cat_name   = array();
            $cat_id            = $category['productCategoryID'];
            $parent_cat_name[] = $this->fn_html_entity_decode($category['productCategoryName']);
            $level             = $category['categoryLevel'];
            for ($i = 1; $i < $level; $i++) {
                $parent_catid      = $this->fn_exim_get_cat_parent_id($cat_id);
                $parent_cat_name[] = $this->fn_html_entity_decode($this->ObjDatabase->getField("SELECT " . DB_PREFIX . "product_category_details.productCategoryName FROM " . DB_PREFIX . "product_category_details 
													WHERE   languageID = '" . $lang_code . "' AND productCategoryID='" . $parent_catid . "'"));
                $cat_id            = $parent_catid;
            }
            $cat_tree = array_reverse($parent_cat_name);
            $result[] = implode($item_delimiter, $cat_tree);
        }
        return implode($set_delimiter, $result);
    }
    function fn_exim_get_cat_parent_id($cat_id) {
        return $this->ObjDatabase->getField("SELECT productCategoryParent FROM " . DB_PREFIX . "product_categories 
											WHERE productCategoryID ='" . $cat_id . "'");
    }
    public function listProductTocategoryDetails($languageIDs, $productID, $status = '') {
        $sql = "
				SELECT
						productToCat.*,
						productCatDet.productCategoryName,
						categoryLevel
						FROM
						" . DB_PREFIX . "product_to_category AS productToCat
					LEFT JOIN
						" . DB_PREFIX . "product_categories AS productCat
							ON	(
								productCat.productCategoryID=	productToCat.productCategoryID
								 AND productCat.productCategoryStatus='Active')
					LEFT JOIN
						" . DB_PREFIX . "product_category_details AS productCatDet 
							ON	(
								productToCat.productCategoryID=productCatDet.productCategoryID
							)
				WHERE
					productID='" . $productID . "'
					AND 
					productCatDet.languageID = '" . $languageIDs['Current'] . "'";
        return $this->ObjDatabase->readValues($sql);
    }
    
//    public function fn_exim_get_productlock($product_id,$data,$productStatus="Active"){
//        if($productStatus=="Inactive")
//            $productLock    =   "No";
//        else
//            $productLock    =   "Yes";
//       
//        return $productLock;
//    }
//    
//    public function fn_exim_set_productlock($product_id,$productLock){
//        $this->ObjDatabase->setQuery("UPDATE `" . DB_PREFIX . "products` SET `productLock` ='Yes' WHERE productID ='" . $product_id . "'");
//    }
    public function updateProductLock($productStatus,$productID){
        if($productStatus=="Active" || $productStatus =='')
            $productLock    =   "No";
        else
            $productLock    =   "Yes";
        $this->ObjDatabase->setQuery("UPDATE `" . DB_PREFIX . "products` SET `productLock` ='".$productLock."' WHERE productID ='" . $productID . "'");
    }
}

