package kz.cafe.admin.autoimport;

import java.io.*;
import java.util.*;
import kz.cafe.admin.autoimport.exceptions.*;
import kz.cafe.admin.autoimport.model.*;
import kz.cafe.constants.*;
import kz.cafe.db.*;
import kz.cafe.db.model.*;
import kz.cafe.logs.*;
import org.apache.commons.logging.*;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.ss.usermodel.*;

public class Importer{
   private static Log log = LogFactory.getLog(Importer.class);
   private static final String LOG = "[XLS Import] ";
   
   
   private static Map<String, PCafe>       mapCafes       = new HashMap<String, PCafe>();
   private static Map<String, PCategory>   mapCategories  = new HashMap<String, PCategory>();
   private static Map<String, PIngredient> mapIngredients = new HashMap<String, PIngredient>();
   private static List<PMeal>              listMeals      = new ArrayList<PMeal>();  
   
   
   public static List<String> importLogic(String sFile) throws ImportException{
      List<String> listErrors = new ArrayList<String>();
      
      /** Create a workbook using the File System **/
      HSSFWorkbook myWorkBook;
      try{
         FileInputStream myInput = new FileInputStream(sFile);

         /** Create a POIFSFileSystem object **/
         POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput);

         myWorkBook = new HSSFWorkbook(myFileSystem);
      }
      catch (Exception e){
         throw new ImportException(-1, -1, "I/O problem:" + e.toString());
      }
      
      /** Get the first sheet from workbook **/
      HSSFSheet mySheet = myWorkBook.getSheetAt(0);
      

      /** We now need something to iterate through the cells. **/
      Iterator<Row> rowIter = mySheet.rowIterator();


      PCafe pCafe = null;
      
      HSSFRow myRow;
      int iRowNumber = 0;
      while (rowIter.hasNext()){
         
         int iCellNumber = 0;
         try{
            myRow = (HSSFRow) rowIter.next();
            
            iRowNumber++;
            
            if(iRowNumber == 1){
               //let's skip the header row
               continue;
            }
            
   
            int iIndex;
            Iterator<Cell> cellIter = myRow.cellIterator();
   
            HSSFCell cellTmp = (HSSFCell) cellIter.next();
            iCellNumber++;            
            
            iIndex = cellTmp.getColumnIndex();
            
            PCategory pCategory;
            if(iIndex == 0){
               PCafe tmp = processCafe(myWorkBook, cellTmp);
               if(tmp == null){
               }
               else{
                  pCafe = tmp;
               }
               
               HSSFCell cellCategory = (HSSFCell) cellIter.next();
               pCategory = processCategory(myWorkBook, cellCategory);            
               
            }
            else{
               pCategory = processCategory(myWorkBook, cellTmp);            
            }
            
            
            if(pCategory == null){
               continue;
            }
            
            
            
            PMeal pMeal = new PMeal();
            HSSFCell cellMeal = (HSSFCell) cellIter.next();
            iCellNumber++;            
            
            String sMeal = cellMeal.getStringCellValue();
            if(sMeal != null && !"".endsWith(sMeal)){
               
               pMeal = new PMeal();
               pMeal.name_ = sMeal.toLowerCase();
               pMeal.name_rus  = sMeal;
               pMeal.name_eng = myWorkBook.getSheetAt(1).getRow(cellMeal.getRowIndex()).getCell(cellMeal.getColumnIndex()).getStringCellValue();
               pMeal.name_kaz = myWorkBook.getSheetAt(2).getRow(cellMeal.getRowIndex()).getCell(cellMeal.getColumnIndex()).getStringCellValue();
               
               pMeal.category = pCategory;
               pMeal.cafe = pCafe;
               
               listMeals.add(pMeal);
            }
            else{
               //Seems there is on meal at all
               //Let's skip it
               continue;
            }
            
            HSSFCell cellDescription = (HSSFCell) cellIter.next();
            iCellNumber++;
            
            HSSFCell cellWeight;
            HSSFCell cellPrice;
            
            
            if(cellDescription.getColumnIndex() == 3){
               pMeal.description_rus = myWorkBook.getSheetAt(0).getRow(cellDescription.getRowIndex()).getCell(cellDescription.getColumnIndex()).getStringCellValue();
               pMeal.description_eng = myWorkBook.getSheetAt(1).getRow(cellDescription.getRowIndex()).getCell(cellDescription.getColumnIndex()).getStringCellValue();
               pMeal.description_kaz = myWorkBook.getSheetAt(2).getRow(cellDescription.getRowIndex()).getCell(cellDescription.getColumnIndex()).getStringCellValue();
               
               cellWeight = (HSSFCell) cellIter.next();
            }
            else{
               cellWeight = cellDescription; 
            }
            iCellNumber++;            

            
            
            if(cellWeight.getColumnIndex() == 4){
               pMeal.weight_rus = myWorkBook.getSheetAt(0).getRow(cellWeight.getRowIndex()).getCell(cellWeight.getColumnIndex()).getStringCellValue();
               pMeal.weight_eng = myWorkBook.getSheetAt(1).getRow(cellWeight.getRowIndex()).getCell(cellWeight.getColumnIndex()).getStringCellValue();
               pMeal.weight_kaz = myWorkBook.getSheetAt(2).getRow(cellWeight.getRowIndex()).getCell(cellWeight.getColumnIndex()).getStringCellValue();
               
               cellPrice = (HSSFCell) cellIter.next();
            }
            else{
               cellPrice = cellWeight; 
            }
            iCellNumber++;            
            
            
            try{
               double dblPrice = cellPrice.getNumericCellValue();
               pMeal.price = new Double(dblPrice * 100).intValue();
            }
            catch (Exception e){
               //something is wrong
               //doesnot matter
            }
            
            
            if(cellIter.hasNext()){
               HSSFCell cellIngredients = (HSSFCell) cellIter.next();
               iCellNumber++;            
               
               String sIngredientsRus = cellIngredients.getStringCellValue();
               
               if(sIngredientsRus != null && !"".endsWith(sIngredientsRus)){
                  String sIngredientsEng = myWorkBook.getSheetAt(1).getRow(cellIngredients.getRowIndex()).getCell(cellIngredients.getColumnIndex()).getStringCellValue();
                  String sIngredientsKaz = myWorkBook.getSheetAt(2).getRow(cellIngredients.getRowIndex()).getCell(cellIngredients.getColumnIndex()).getStringCellValue();
                  
                  String[] arrstrIngredientsRus = sIngredientsRus.split(","); 
                  String[] arrstrIngredientsEng = sIngredientsEng.split(","); 
                  String[] arrstrIngredientsKaz = sIngredientsKaz.split(",");
                  
                  if(arrstrIngredientsRus.length == arrstrIngredientsEng.length
                       && arrstrIngredientsEng.length == arrstrIngredientsKaz.length){
                     
                     int iIngredient = 0;
                     for(String sIngredient : arrstrIngredientsRus){
                        sIngredient = sIngredient.trim();
                        PIngredient pIngredient = mapIngredients.get(sIngredient);
   
                        if(pIngredient == null){
                           pIngredient = new PIngredient();
                           pIngredient.name_ = sIngredient.toLowerCase();
                           pIngredient.name_rus = sIngredient;
                           pIngredient.name_eng = arrstrIngredientsEng[iIngredient].trim();
                           pIngredient.name_kaz = arrstrIngredientsKaz[iIngredient].trim();
                           mapIngredients.put(pIngredient.name_, pIngredient);
                        }
   
                        pMeal.setIngrediens.add(pIngredient);
                        iIngredient++;
                     }
                     
                  }
                  else{
                     listErrors.add("русский, английский и казахский листы НЕ совпадают по кол-ву ингредиентов в ячейке "
                                         + (cellIngredients.getRowIndex() + 1) + ":" + (cellIngredients.getColumnIndex() + 1));
                     continue;
                  }
               }
            }
         }
         catch(Throwable e){
            e.printStackTrace();
            throw new ImportException(iRowNumber, iCellNumber, e.toString());
         }
      }
      
      
      if(listErrors.size() > 0){
         
         return listErrors;
      }
   
   
      //let's log the things
      LogTableFormatter ltf = new LogTableFormatter(1, true);
      ltf.addCell("RUS");
      ltf.addCell("ENG");
      ltf.addCell("KAZ");
      ltf.newSeparator();      
      for(PMeal pMeal : listMeals){
         ltf.addCell(pMeal.cafe.name_rus);
         ltf.addCell(pMeal.cafe.name_eng);
         ltf.addCell(pMeal.cafe.name_kaz);
         
         ltf.addCell(pMeal.category.name_rus);
         ltf.addCell(pMeal.category.name_eng);
         ltf.addCell(pMeal.category.name_kaz);
         
         ltf.addCell(pMeal.name_rus);
         ltf.addCell(pMeal.name_eng);
         ltf.addCell(pMeal.name_kaz);
         
         ltf.addCell(pMeal.setIngrediens);
         
         ltf.br();         
      }
      
      log.info(LOG + "\n" + ltf.toString());
      
      
      
      
      
      for(PMeal pMeal : listMeals){
         MCafe mCafe = MongoService.ds.find(MCafe.class,
                                            "name_." + InterfaceConstants.LANGS.RU,
                                            pMeal.cafe.name_).get();
         if(mCafe == null){
            mCafe = new MCafe();
            mCafe.ID = MongoService.getUniqueID(MCafe.class);
            mCafe.name.put(InterfaceConstants.LANGS.RU, pMeal.cafe.name_rus);
            mCafe.name.put(InterfaceConstants.LANGS.EN, pMeal.cafe.name_eng);
            mCafe.name.put(InterfaceConstants.LANGS.KZ, pMeal.cafe.name_kaz);
         }
         mCafe.deleted = false;
         MongoService.save(mCafe);
         
         
         
         
         MCourseCategory mCourseCategory = MongoService.ds.find(MCourseCategory.class, "name_." + InterfaceConstants.LANGS.RU, pMeal.category.name_).get();
         if(mCourseCategory == null){
            mCourseCategory = new MCourseCategory();
            mCourseCategory.ID = MongoService.getUniqueID(MCourseCategory.class);
            mCourseCategory.name.put(InterfaceConstants.LANGS.RU, pMeal.category.name_rus);
            mCourseCategory.name.put(InterfaceConstants.LANGS.EN, pMeal.category.name_eng);
            mCourseCategory.name.put(InterfaceConstants.LANGS.KZ, pMeal.category.name_kaz);
         }
         mCourseCategory.deleted = false;
         MongoService.save(mCourseCategory);
         

         
         
         
         MCourse mCourse = MongoService.ds.find(MCourse.class, "name_." + InterfaceConstants.LANGS.RU, pMeal.name_)
                                          .filter(MCourse.F_CID, mCafe.ID)
                                          .get();
         if(mCourse == null){
            mCourse = new MCourse();
            mCourse.ID = MongoService.getUniqueID(MCourse.class);
            mCourse.name.put(InterfaceConstants.LANGS.RU, pMeal.name_rus);
            mCourse.name.put(InterfaceConstants.LANGS.EN, pMeal.name_eng);
            mCourse.name.put(InterfaceConstants.LANGS.KZ, pMeal.name_kaz);
         }
            
         if(pMeal.description_rus == null){
            //we do not set empty descriptions
         }
         else{
            mCourse.description.put(InterfaceConstants.LANGS.RU, pMeal.description_rus);
         }
         if(pMeal.description_eng == null){
            //we do not set empty descriptions
         }
         else{
            mCourse.description.put(InterfaceConstants.LANGS.EN, pMeal.description_eng);
         }
         if(pMeal.description_kaz == null){
            //we do not set empty descriptions
         }
         else{
            mCourse.description.put(InterfaceConstants.LANGS.KZ, pMeal.description_kaz);
         }
         
         mCourse.weight2.put(InterfaceConstants.LANGS.RU, pMeal.weight_rus);
         mCourse.weight2.put(InterfaceConstants.LANGS.EN, pMeal.weight_eng);
         mCourse.weight2.put(InterfaceConstants.LANGS.KZ, pMeal.weight_kaz);

         mCourse.CID = mCafe.ID;
         mCourse.category = mCourseCategory.ID;
         
         
         mCourse.deleted = false;
         
         
         
         //Remove them all
         mCourse.ingredient.clear();
         
         for(PIngredient pIngredient : pMeal.setIngrediens){
            MIngredient mIngredient = MongoService.ds.find(MIngredient.class,
                                                           "name_." + InterfaceConstants.LANGS.RU,
                                                           pIngredient.name_).get();
            
            if(mIngredient == null){
               mIngredient = new MIngredient();
               mIngredient.ID = MongoService.getUniqueID(MIngredient.class);
               mIngredient.name.put(InterfaceConstants.LANGS.RU, pIngredient.name_rus);
               mIngredient.name.put(InterfaceConstants.LANGS.EN, pIngredient.name_eng);
               mIngredient.name.put(InterfaceConstants.LANGS.KZ, pIngredient.name_kaz);
               
               
               try{
                  MongoService.save(mIngredient);
                  mCourse.ingredient.add(mIngredient.ID);
               }
               catch (Exception e){
                  throw new Error(pIngredient.name_rus + ", " + pIngredient.name_eng + ", " + pIngredient.name_kaz, e);
                  //continue;
               }
            }
            else{
               mIngredient.deleted = false;
               MongoService.save(mIngredient);
               mCourse.ingredient.add(mIngredient.ID);
            }
         }
         
         mCourse.price = pMeal.price;
         mCourse.ownerID = mCafe.ownerID; 
         MongoService.save(mCourse);
      }
      
      return listErrors;      
   }
   

   
   
   private static PCafe processCafe(HSSFWorkbook myWorkBook, HSSFCell cellCafe){
      String sCafe = cellCafe.getStringCellValue();
      if(sCafe != null && !"".endsWith(sCafe)){
         // A new organiztion
         PCafe pCafe = new PCafe();
         pCafe.name_    = sCafe.toLowerCase();
         pCafe.name_rus = sCafe;
         pCafe.name_eng = myWorkBook.getSheetAt(1).getRow(cellCafe.getRowIndex()).getCell(cellCafe.getColumnIndex()).getStringCellValue();
         pCafe.name_kaz = myWorkBook.getSheetAt(2).getRow(cellCafe.getRowIndex()).getCell(cellCafe.getColumnIndex()).getStringCellValue();
         mapCafes.put(pCafe.name_, pCafe);
         
         return pCafe;
      }
      else{
         return null;
      }
   }
   
   
   
   private static PCategory processCategory(HSSFWorkbook myWorkBook, HSSFCell cellCategory){
      String sCategory = cellCategory.getStringCellValue();
      if(sCategory != null && !"".endsWith(sCategory)){
         PCategory pCategory = mapCategories.get(sCategory.toLowerCase());
         
         if(pCategory == null){
            //A new category
            pCategory = new PCategory();
            pCategory.name_ = sCategory.toLowerCase();
            pCategory.name_rus  = sCategory;
            pCategory.name_eng = myWorkBook.getSheetAt(1).getRow(cellCategory.getRowIndex()).getCell(cellCategory.getColumnIndex()).getStringCellValue();
            pCategory.name_kaz = myWorkBook.getSheetAt(2).getRow(cellCategory.getRowIndex()).getCell(cellCategory.getColumnIndex()).getStringCellValue();
            
            mapCategories.put(pCategory.name_, pCategory);
         }
         
         return pCategory;
      }
      
      return null;
   }
}
