/*
 * Created by joao.fialho
 * Date: 17/Jul/2006
 * Time: 14:57:22
 */
package pt.link.ee.catalog.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilDateTime;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.base.util.UtilProperties;
import org.ofbiz.entity.GenericCreateException;
import org.ofbiz.entity.GenericDelegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericFindException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.util.ByteWrapper;
import org.ofbiz.service.DispatchContext;
import org.ofbiz.service.ServiceUtil;


/**
 * @author joao.fialho
 * @date 17/Jul/2006
 */
public class BannerService {
	/**
	 */
	public final static String module = BannerService.class.getName();
    
    /**
     */
    private static final int CREATE_BANNER = 0;
    /**
     */
    private static final int UPDATE_BANNER = 1;
	
   /* private static String characterEncoding = null;
    
    
    public static String setCharacterEncodingEvent(HttpServletRequest request, HttpServletResponse response) {
        characterEncoding = request.getCharacterEncoding();
        
        return "success";
    }*/
	
    /**
     * According to the action parameter, it creates or updates a Banner
     * 
     * @param dispatchContext
     * @param parameters
     * @param action
     * @return
     */
    private static Map updateOrCreateBanner(DispatchContext dispatchContext, Map parameters, int action) {
        try {
            BannerInfo bannerInfo = new BannerInfo(dispatchContext.getDelegator(), parameters);
            if(action == CREATE_BANNER)
                bannerInfo.create();
            else if(action == UPDATE_BANNER)
                bannerInfo.update();
            else
                return ServiceUtil.returnError("Unknown action: " + action);
            
        } catch (IOException ioe) {
            final String msg = "Problem uploading Image";
            Debug.logError(ioe, msg, module);
            return ServiceUtil.returnError(msg + ": " + ioe.getMessage());
        
        } catch (GenericEntityException gee) {
            final String msg = "Problem storing the Banner";
            Debug.logError(gee, msg, module);
            return ServiceUtil.returnError(msg + ": " + gee.getMessage());

        }
        
        return ServiceUtil.returnSuccess();
        
    }
    
	/**
     * <p>Service interface method.</p>
     * <p>Creates a new Banner</p>
     * 
	 * @param dispatchContext
	 * @param parameters
	 * @return 
	 */
    public static Map createBanner(DispatchContext dispatchContext, Map parameters) {
        Debug.log("createBanner(DispatchContext, Map)", module);
        return updateOrCreateBanner(dispatchContext, parameters, CREATE_BANNER);
    }

    /**
     * <p>Service interface method.</p>
     * <p>Updates an existing Banner</p>
     * 
     * @param dispatchContext
     * @param parameters
     * @return
     */
    public static Map updateBanner(DispatchContext dispatchContext, Map parameters) {
        Debug.log("updateBanner(DispatchContext, Map)", module);
        return updateOrCreateBanner(dispatchContext, parameters, UPDATE_BANNER);
    }
    
    /**
     * <p>Service interface method.</p>
     * <p>Deletes an existing Banner.
     * Instead of deleting it permanently from the Database, only the reference to the productStore is severed.</p>
     * 
     * @param dispatchContext
     * @param parameters
     * @return
     */
    public static Map deleteBanner(DispatchContext dispatchContext, Map parameters) {
        Debug.log("deleteBanner(DispatchContext, Map)", module);
        try {
            BannerInfo bannerInfo = new BannerInfo(dispatchContext.getDelegator(), (String) parameters.get("bannerId"));
            bannerInfo.dissociateProductStore();
            
        } catch (GenericEntityException gee) {
            final String msg = "Problem deleting the Banner";
            Debug.logError(gee, msg, module);
            return ServiceUtil.returnError(msg + ": " + gee.getMessage());
        }
        return ServiceUtil.returnSuccess();
    }
    
    /**
     * <p>Service interface method.</p>
     * <p>Updates the banner on a Category</p>
     * 
     * @param dispatchContext
     * @param parameters
     * @return
     * @throws Exception
     */
    public static Map updateCategoryBanner(DispatchContext dispatchContext, Map parameters) throws Exception {
        Debug.log("updateCategoryBanner(DispatchContext, Map)", module);
        
        String prodCatalogId = (String) parameters.get("prodCatalogId");
        String productCategoryId = (String) parameters.get("productCategoryId");
        String prodCatalogCategoryTypeId = (String) parameters.get("prodCatalogCategoryTypeId");
        String fromDate = (String) parameters.get("fromDate");
        String bannerId = (String) parameters.get("bannerId");
        
        Timestamp fromDateTimestamp = UtilDateTime.toTimestamp(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(fromDate));
        GenericValue prodCatalogCategory = dispatchContext.getDelegator().findByPrimaryKey("ProdCatalogCategory", UtilMisc.toMap(
                "prodCatalogId", prodCatalogId,
                "productCategoryId", productCategoryId,
                "prodCatalogCategoryTypeId", prodCatalogCategoryTypeId,
                "fromDate", fromDateTimestamp
                ));
        
        if(prodCatalogCategory == null) {
            return ServiceUtil.returnError("Category not found!");
        } else {
            //Nullify the banner if it contains an empty String
            if((bannerId != null) && (bannerId.length() == 0)) {
                bannerId = null;
            }
            prodCatalogCategory.set("bannerId", bannerId);
            prodCatalogCategory.store();
        }


        return ServiceUtil.returnSuccess();
    }

	
	/**
	 * Contains all the validated Banner information to be manipulated
     * 
	 * @author joao.fialho
	 * @date 17/Jul/2006
	 */
	private static class BannerInfo {
		private static final String CATALOG_PROPERTIES = "catalog";
		private static final String DEFAULT_EXTENSION = ".gif";
        //private static final int BUFFER_SIZE = 4096;
        
        //Persistent properties
		private String bannerId = null;
		private String productStoreId = null;
		private String bannerImageUrl = null;
		private String bannerReferencedUrl = null;
        
        //Auxiliar properties
		private ByteWrapper imageByteWrapper = null;
		private String imageFilePath = null;
		
        private GenericDelegator delegator = null;
        
		/**
         * Creates a new BannerInfo, initializing it according to the parameters map and the catalog properties
         * 
		 * @param parameters
		 * @throws GenericEntityException 
		 */
		private BannerInfo(GenericDelegator delegator, Map parameters) throws GenericEntityException {
			super();
            init(delegator, (String) parameters.get("bannerId"));

			this.productStoreId = (String) parameters.get("productStoreId");
			this.bannerReferencedUrl = (String) parameters.get("bannerReferencedUrl");
			
			this.imageByteWrapper = (ByteWrapper) parameters.get("imageFile");
            
			if(this.imageByteWrapper != null) {
    			//Extract the Image file Location
    			String originalImagePathFile = (String) parameters.get("originalImageFilePath");
                String extension = (originalImagePathFile != null && originalImagePathFile.length() >= 0) ?
                        originalImagePathFile.substring(originalImagePathFile.lastIndexOf('.')) : DEFAULT_EXTENSION;
    			
                String locationBanners = UtilProperties.getPropertyValue(CATALOG_PROPERTIES, "location.banners");
    
                String imageServerPath = UtilProperties.getPropertyValue(CATALOG_PROPERTIES, "image.server.path");
                String imageUrlPrefix = UtilProperties.getPropertyValue(CATALOG_PROPERTIES, "image.url.prefix");
                
                String fileLocation = locationBanners + "/" + this.productStoreId + "/";
                String imageFileName = this.bannerId + extension;
                
                this.imageFilePath = imageServerPath + "/" + fileLocation + imageFileName;
                this.bannerImageUrl = imageUrlPrefix + "/" + fileLocation + imageFileName;
            }
		}
        
        /**
         * Creates a new Banner info, based on an existing GenericValue
         * 
         * @param delegator
         * @param bannerId
         * @throws GenericEntityException
         */
        private BannerInfo(GenericDelegator delegator, String bannerId) throws GenericEntityException {
            super();
            init(delegator, bannerId);
            //TODO: read the rest of the parameters using the delegator
        }

        /**
         * @param delegator
         * @param bannerId
         * @throws GenericEntityException
         */
        private void init(GenericDelegator delegator, String bannerId) throws GenericEntityException {
            if(delegator == null)
                throw new GenericEntityException("Null GenericDelegator!");
            
            if((bannerId == null) || (bannerId.length() <= 0) )
                throw new GenericEntityException("Empty bannerId!");
            
            this.delegator = delegator;

            this.bannerId = bannerId;
        }
        
        /**
         * Uploads the image contents
         * 
         * @throws IOException
         */
        private void uploadImageFile() throws IOException {
            if(this.imageByteWrapper != null) {
                File imageFile = new File(this.imageFilePath);
                //Create the parent directory, if it doesn't exist
                File parentDir = imageFile.getParentFile();
                if(parentDir != null && !parentDir.exists()) {
                    parentDir.mkdirs();
                }
                
                FileOutputStream fos = null;
                try {
                    byte[] bytesToWrite = this.imageByteWrapper.getBytes();
                    if(bytesToWrite != null) {
                        fos = new FileOutputStream(imageFile);
                        fos.write(bytesToWrite, 0, bytesToWrite.length);
                    }
                } catch (FileNotFoundException e) {
                    Debug.logError(e, "pt.link.ee.catalog.service.BannerService$BannerInfo.uploadImageFile()", module);
                    throw e;
                } catch (IOException e) {
                    Debug.logError(e, "pt.link.ee.catalog.service.BannerService$BannerInfo.uploadImageFile()", module);
                    throw e;
                } finally {
                    if(fos != null) {
                        fos.flush();
                        fos.close();
                    }
                }
            }
        }
        
        /**
         * Get the GenericValue Banner that this info represents
         * 
         * @return
         * @throws GenericEntityException
         */
        private GenericValue getAsGenericValue() throws GenericEntityException {            
            GenericValue banner = this.delegator.findByPrimaryKey("Banner", UtilMisc.toMap("bannerId", this.bannerId));
            return banner;
        }
        
        /**
         * Creates and stores a new Banner
         * 
         * @throws IOException if there's any error uploading the image file
         * @throws GenericEntityException if there is no image file, or if any other error occurs when creating it
         */
        private void create() throws IOException, GenericEntityException {
            if(this.imageByteWrapper == null) {
                throw new GenericCreateException("Null Image!");
            }
            this.uploadImageFile();
            GenericValue banner = this.delegator.create("Banner", UtilMisc.toMap(
                    "bannerId", this.bannerId,
                    "productStoreId", this.productStoreId,
                    "bannerReferencedUrl", this.bannerReferencedUrl,
                    "bannerImageUrl", this.bannerImageUrl
                    ));
            banner.store();
        }
        
        /**
         * Updates a existing Banner
         * 
         * @throws IOException if there's any error uploading the image file
         * @throws GenericEntityException if the banner doesn't exist, or if any other error occurs when updating it it
         */
        private void update() throws IOException, GenericEntityException {
            GenericValue banner = this.getAsGenericValue();
            if(banner == null)
                throw new GenericFindException("Banner " + this.bannerId + " not found!");
            
            this.uploadImageFile();
            
            banner.set("bannerReferencedUrl", this.bannerReferencedUrl);
            if(this.bannerImageUrl != null) {
                //If the banner is null, it means it was unchanged
                banner.set("bannerImageUrl", this.bannerImageUrl);
            }
            
            banner.store();
        }
        
        /**
         * Dissociates the ProductStore from the Banner, rendering it an "orphan"
         * 
         * @throws GenericEntityException
         */
        private void dissociateProductStore() throws GenericEntityException {
            GenericValue banner = this.getAsGenericValue();
            if(banner != null) {
                //Dissociate the banner from the categories
                List relatedCategories = banner.getRelated("ProdCatalogCategory");
                if((relatedCategories != null) && (!relatedCategories.isEmpty())) {
                    ListIterator iterator = relatedCategories.listIterator();
                    while(iterator.hasNext()) {
                        GenericValue category = (GenericValue) iterator.next();
                        category.set("bannerId", null);
                        category.store();
                    }
                }
                //Dissociate the ProductStore from the Banner
                banner.set("productStoreId", null);
                banner.store();
            }
        }
        
//        /**
//         * @param bannerImageUrl
//         */
//        private void deleteImageFile(String bannerImageUrl) {
//            if((bannerImageUrl != null) && (bannerImageUrl.length() > 0)) {
//                File fileImage = new File(bannerImageUrl);
//                if(fileImage.exists()) {
//                    fileImage.delete();
//                }
//            }
//        }
//        
//        /**
//         * @param delegator
//         * @return number of rows affected
//         * @throws GenericEntityException
//         */
//        private int delete(GenericDelegator delegator) throws GenericEntityException {
//            GenericValue banner = this.getAsGenericValue(delegator);
//            if(banner == null)
//                throw new GenericFindException("Banner " + this.bannerId + " not found!");
//            
//            //Remove the Banner
//            int affectedRows = delegator.removeValue(banner, true);
//            //Delete the Image
//            if(affectedRows > 0) {
//                deleteImageFile(banner.getString("bannerImageUrl"));
//            }
//            
//            return affectedRows;
//        }

	}
	
}
