package dendrarium.portal.stats;

import dendrarium.core.entities.User;
import dendrarium.portal.MenuItem;
import java.io.Serializable;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.hibernate.Session;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.faces.FacesMessages;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Identity;

/**
 *
 * @author Tomasz Badowski
 */
@Name("statsDendrolog")
@Scope(ScopeType.SESSION)
public class StatsDendrolog implements Serializable {

    @Out(required = false)
    List<MenuItem> statsDendrologMenuItems;

    @Logger
    Log log;

    @In
    Session session;

    /*    @Factory(value = "myDone")
    @Observer("tbpchangestate")
    public void getMyDone(){
    this.myDone = (Long) session.getNamedQuery("myDoneAnswersNumber")
    .setParameter("user", user).uniqueResult();
    }

    @Factory(value = "myAll")
    @Observer("tbpchangestate")
    public void getMyAll(){
    this.myAll = (Long) session.getNamedQuery("myAnswersNumber")
    .setParameter("user", user).uniqueResult();
    }
     */
    @In
    private User user;

    @In
    private Identity identity;

    @Out(required = false)
    Stats userStats;

    @Out(required = false)
    Long myNieprzydzielone;

    @Out(required = false)
    Long myAllAnsNum;

    @Out(required = false)
    Long myAllNeedConfNum;

    @Out(required = false)
    Long myAllDoneAnsNum;

    @Out(required = false)
    Long myFullNum;

    @Out(required = false)
    Long mySpecialNum;

    @Out(required = false)
    Long myCollisionsNum;

    @Out(required = false)
    Long myNotAccepted;

    @Out(required = false)
    Long myAgreements;

    @Out(required = false)
    Double myCollisionRatio;

    @Out(required = false)
    Long myNoTree;

    @Out(required = false)
    Long myRejected;

    @Out(required = false)
    Long nieprzydzielone;

    @Out(required = false)
    Long allAnsNum;

    @Out(required = false)
    Long allNeedConfNum;

    @Out(required = false)
    Long allDoneAnsNum;

    @Out(required = false)
    Long fullNum;

    @Out(required = false)
    Long specialNum;

    @Out(required = false)
    Long collisionsNum;

    @Out(required = false)
    Long notAccepted;
   
    @Out(required = false)
    Long agreementsNum;

    @Out(required = false)
    Double collisionRatio;

    @Out(required = false)
    Long noTree;

    @Out(required = false)
    Long rejected;

    @Out(required = false)
    List<Long> monthDoneList;

    @Out(required = false)
    List<Integer> monthDoneNums;

    @Out(required = false)
    DateChoice dateChoice = new DateChoice();

    @In
    FacesMessages facesMessages;

    @Factory("dateChoice")
    public DateChoice getDateChoice() {
        return dateChoice;
    }

    public void setDateChoice(DateChoice dateChoice) {
        this.dateChoice = dateChoice;
    }

//    @Factory(value = "dateChoice")
//    public void getDateChoice() {
//        }
//        dateChoice.setChoiceYears(choiceYears);
//    }
//    @RaiseEvent("newDate")
    public void selectDate() {
        /* Dostosowanie tabelki do nowej daty */
        if (session == null || user == null) {
            facesMessages.add("Brak session lub usera!");
            return;
        }
        getMonthDoneList();
        getMonthDoneNums();
    //   log.info("AAA\n");
    }

    public List<Long> makeMonthDoneList(Calendar cal, User u, Session s,
            Boolean asSuper) {
        /*
         * parametr DAY_OF_MONTH kalendarza ustawiony na ostatni interesujący nas dzień
         * miesiąca, parametry year i month na właściwy rok i miesiąc
         */
        Calendar cal2 = Calendar.getInstance();
//      cal2.set( cal2.get( Calendar.YEAR), cal2.get(Calendar.MONTH), 1, 0,0);
        Date startDate;
        Date finishDate;
        cal2.set(Calendar.YEAR, cal.get(Calendar.YEAR));
        cal2.set(Calendar.MONTH, cal.get(Calendar.MONTH));
        cal2.set(Calendar.DAY_OF_MONTH, 1);
        monthDoneList = new LinkedList<Long>();
        Long numAns;
        cal2.set(Calendar.HOUR, 0);
        cal2.set(Calendar.MINUTE, 0);
        int k = (cal.get(Calendar.DAY_OF_MONTH));// > 10) ? 10 :cal.get(Calendar.DAY_OF_MONTH);
        for (int i = 1 ; i <= k ; i++) {
            startDate = new Date(cal2.getTimeInMillis());
//            cal2.set(Calendar.HOUR, 23);
//            cal2.set(Calendar.MINUTE, 59);
            cal2.add(Calendar.DAY_OF_MONTH, 1);
            finishDate = new Date(cal2.getTimeInMillis());
            if (asSuper) {
                numAns = (Long) s.getNamedQuery("SuperNumAnswersInterval").setParameter("user", u).setTimestamp("startDate", startDate).setTimestamp("finishDate", finishDate).uniqueResult();
            } else {
                numAns = (Long) s.getNamedQuery("NumAnswersInterval").setParameter("user", u).setTimestamp("startDate", startDate).setTimestamp("finishDate", finishDate).uniqueResult();
            }
            monthDoneList.add(numAns);
        }
        return monthDoneList;
    }

    Calendar actCalendar(DateChoice dateChoice) {
        Calendar cal = Calendar.getInstance();
        if (cal.get(Calendar.MONTH) != dateChoice.getCurrentMonth().ordinal()) {
            cal.set(Calendar.MONTH, dateChoice.getCurrentMonth().ordinal() + 1);
            cal.set(Calendar.DAY_OF_MONTH, 1);
            cal.add(Calendar.DAY_OF_MONTH, -1);
        //log.info("ostatni dzien miesiaca: " + cal.get(Calendar.DAY_OF_MONTH) + "\n\n\n");
        }
        cal.set(Calendar.YEAR, dateChoice.getCurrentYear());
        return cal;
    }

    //@Factory(value = "monthDoneList")
    //@Observer({"tbpchangestate"}) //, "newDate"})
//    @Observer("tbpchangestate")
    public List<Long> getMonthDoneList() {
        Calendar cal = actCalendar(dateChoice);
        monthDoneList = makeMonthDoneList(cal, user, session, false);
        if (monthDoneList == null) {
            log.info("monthDoneList jest null\n");
        }
        return monthDoneList;
    //log.info("monthDoneList ma dlugosc:" + monthDoneList.size() + "\n");
    }

    //answer.setSelectDate(now);
//        int year = cal.get(Calendar.YEAR);
//        int month = cal.get(Calendar.MONTH)+1;
//        Long last = new Long(-1);
//        Long first = new Long(-1);
//        startDate = new Date(cal2.getTimeInMillis());
//        cal2.add(Calendar.DAY_OF_MONTH,10);
//        finishDate = new Date(cal2.getTimeInMillis());
//        if (now.after(startDate) && now.before(finishDate)){
//            first = (Long) session.getNamedQuery("NumAnswersInterval").setParameter("user", user).setTimestamp("startDate", startDate).setTimestamp("finishDate", finishDate).uniqueResult();
//        }
    //        if (now.after(startDate)){
//          first = new Long(13);
//        }
//        if (now.before(finishDate)){
//          last = new Long(14);
//        }
//        Long numAns;
//        for (int i = 1; i <= cal.get(Calendar.DATE); i++) {
//            startDate = new Date(cal2.getTimeInMillis());
//            cal2.add(Calendar.DAY_OF_MONTH, 1);
//            finishDate = new Date(cal2.getTimeInMillis());
//            numAns = (Long) session.getNamedQuery("NumAnswersInterval")
//                    .setParameter("user", user).setTimestamp("startDate", startDate)
//                    .setTimestamp("finishDate", finishDate).uniqueResult();
//            monthDoneList.add(numAns);
//        }
//        monthDoneList.add(first);
//        monthDoneList.add(last);
//    }
    public List<Integer> makeNumsList(Calendar cal) {
        List<Integer> monthNums = new LinkedList<Integer>();
        for (Integer i = 1 ; i <= cal.get(Calendar.DAY_OF_MONTH) ; i++) {
            monthNums.add(i);
        }
        return monthNums;
    }

    @Factory(value = "monthDoneNums")
//    @Observer("newDate")
    public void getMonthDoneNums() {
        Calendar cal = actCalendar(dateChoice);
        monthDoneNums = makeNumsList(cal);
    }

    //@Factory(value = "myNieprzydzielone")
    //@Observer("tbpchangestate")
    public Long getMyNieprzydzielone() {
        this.myNieprzydzielone = (Long) session.getNamedQuery("myNieprzydzielone1").uniqueResult()
                + (Long) session.getNamedQuery("myNieprzydzielone2").setParameter("user", user).uniqueResult();
        return myNieprzydzielone;
    }

    //@Factory(value = "myAllAnsNum")
    //@Observer("tbpchangestate")
    public Long getMyAllAnsNum() {
        this.myAllAnsNum = (Long) session.getNamedQuery("myAllAnsNum1").setParameter("user", user).uniqueResult() +
                (Long) session.getNamedQuery("myAllAnsNum2").setParameter("user", user).uniqueResult();
        return myAllAnsNum;
    }

    //@Factory(value = "myAllDoneAnsNum")
    //@Observer("tbpchangestate")
    public Long getMyAllDoneAnsNum() {
        this.myAllDoneAnsNum = (Long) session.getNamedQuery("myAllDoneAnsNum1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myAllDoneAnsNum2").setParameter("user", user).uniqueResult();
        return myAllDoneAnsNum;
    }

    //@Factory(value = "myAllNeedConfNum")
    //@Observer("tbpchangestate")
    public Long getMyAllNeedConfNum() {
        this.myAllNeedConfNum = (Long) session.getNamedQuery("myNeedConfNum1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myNeedConfNum2").setParameter("user", user).uniqueResult();
        return myAllNeedConfNum;
    }

    //@Factory(value = "myFullNum")
    //@Observer("tbpchangestate")
    public Long getMyFullNum() {
        this.myFullNum = (Long) session.getNamedQuery("myFullNum1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myFullNum2").setParameter("user", user).uniqueResult();
        return myFullNum;
    }

    //@Factory(value = "mySpecialNum")
    //@Observer("tbpchangestate")
    public Long getMySpecialNum() {
        this.mySpecialNum = (Long) session.getNamedQuery("mySpecialNum1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("mySpecialNum2").setParameter("user", user).uniqueResult();
        return mySpecialNum;
    }

    //@Factory(value = "myCollisionsNum")
    //@Observer("tbpchangestate")
    public Long getMyCollisionsNum() {
        this.myCollisionsNum = (Long) session.getNamedQuery("myCollisionsNum1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myCollisionsNum2").setParameter("user", user).uniqueResult();
        return myCollisionsNum;
    }

    //@Factory(value = "myNotAccepted")
    //@Observer("tbpchangestate")
    public Long getMyNotAccepted() {
        this.myNotAccepted = (Long) session.getNamedQuery("myNotAccepted1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myNotAccepted2").setParameter("user", user).uniqueResult();
        return myNotAccepted;
    }

    //@Factory(value = "myAgreements")
    //@Observer("tbpchangestate")
    public Long getMyAgreements() {
        this.myAgreements = (Long) session.getNamedQuery("myAgreements1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myAgreements2").setParameter("user", user).uniqueResult();
        return myAgreements;
    }

    //@Factory(value = "myCollisionRatio")
    //@Observer("tbpchangestate")
    public Double getMyCollisionRatio() {
        if (myCollisionsNum == null)
            getMyCollisionsNum();
        if (myAllDoneAnsNum == null)
            getMyAllDoneAnsNum();
        Double ratio = 1.0*myCollisionsNum/myAllDoneAnsNum;
        this.myCollisionRatio = (double) (int) ((ratio+0.005)*100.0)/100.0;
        return myCollisionRatio;
    }

    //@Factory(value = "myNoTree")
    //@Observer("tbpchangestate")
    public Long getMyNoTree() {
        this.myNoTree = (Long) session.getNamedQuery("myNoTree1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myNoTree2").setParameter("user", user).uniqueResult();
        return myNoTree;
    }

    //@Factory(value = "myRejected")
    //@Observer("tbpchangestate")
    public Long getMyRejected() {
        this.myRejected = (Long) session.getNamedQuery("myRejected1").setParameter("user", user).uniqueResult() + (Long) session.getNamedQuery("myRejected2").setParameter("user", user).uniqueResult();
        return myRejected;
    }

    /* --- */
    //@Factory(value = "nieprzydzielone")
    //@Observer("tbpchangestate")
    public Long getNieprzydzielone() {
        this.nieprzydzielone = (Long) session.getNamedQuery("nieprzydzielone1").uniqueResult()
                + (Long) session.getNamedQuery("nieprzydzielone2").uniqueResult();
        return nieprzydzielone;
    }

    //@Factory(value = "allAnsNum")
    //@Observer("tbpchangestate")
    public Long getAllAnsNum() {
        this.allAnsNum = (Long) session.getNamedQuery("allAnsNum1").uniqueResult() +
                (Long) session.getNamedQuery("allAnsNum2").uniqueResult();
        return allAnsNum;
    }

    //@Factory(value = "allDoneAnsNum")
    //@Observer("tbpchangestate")
    public Long getAllDoneAnsNum() {
        this.allDoneAnsNum = (Long) session.getNamedQuery("allDoneAnsNum1").uniqueResult() + (Long) session.getNamedQuery("allDoneAnsNum2").uniqueResult();
        return allDoneAnsNum;
    }

    //@Factory(value = "allNeedConfNum")
    //@Observer("tbpchangestate")
    public Long getAllNeedConfNum() {
        this.allNeedConfNum = (Long) session.getNamedQuery("allNeedConfNum1").uniqueResult() + (Long) session.getNamedQuery("allNeedConfNum2").uniqueResult();
        return allNeedConfNum;
    }

    //@Factory(value = "fullNum")
    //@Observer("tbpchangestate")
    public Long getFullNum() {
        this.fullNum = (Long) session.getNamedQuery("fullNum1").uniqueResult() + (Long) session.getNamedQuery("fullNum2").uniqueResult();
        return fullNum;
    }

    //@Factory(value = "specialNum")
    //@Observer("tbpchangestate")
    public Long getSpecialNum() {
        this.specialNum = (Long) session.getNamedQuery("specialNum1").uniqueResult() + (Long) session.getNamedQuery("specialNum2").uniqueResult();
        return specialNum;
    }

    //@Factory(value = "collisionsNum")
    //@Observer("tbpchangestate")
    public Long getCollisionsNum() {
        this.collisionsNum = (Long) session.getNamedQuery("collisionsNum1").uniqueResult() + (Long) session.getNamedQuery("collisionsNum2").uniqueResult();
        return collisionsNum;
    }

    //@Factory(value = "notAccepted")
    //@Observer("tbpchangestate")
    public Long getNotAccepted() {
        this.notAccepted = (Long) session.getNamedQuery("notAccepted1").uniqueResult() + (Long) session.getNamedQuery("notAccepted2").uniqueResult();
        return notAccepted;
    }

    //@Factory(value = "agreementsNum")
    //@Observer("tbpchangestate")
    public Long getAgreementsNum() {
        this.agreementsNum = (Long) session.getNamedQuery("agreements1").uniqueResult() + (Long) session.getNamedQuery("agreements2").uniqueResult();
        return agreementsNum;
    }

    //@Factory(value = "collisionRatio")
    //@Observer("tbpchangestate")
    public Double getCollisionRatio() {
        if (collisionsNum == null)
            getCollisionsNum();
        if (allDoneAnsNum == null)
            getAllDoneAnsNum();
        Double ratio = 1.0*collisionsNum/allDoneAnsNum;
        this.collisionRatio = (double) (int) ((ratio+0.005)*100.0)/100.0;
        return collisionRatio;
    }

    //@Factory(value = "noTree")
    //@Observer("tbpchangestate")
    public Long getNoTree() {
        this.noTree = (Long) session.getNamedQuery("noTree1").uniqueResult() + (Long) session.getNamedQuery("noTree2").uniqueResult();
        return noTree;
    }

    //@Factory(value = "rejected")
    //@Observer("tbpchangestate")
    public Long getRejected() {
        this.rejected = (Long) session.getNamedQuery("rejected1").uniqueResult() + (Long) session.getNamedQuery("rejected2").uniqueResult();
        return rejected;
    }

    /* --- */
    @Factory
    public void getStatsDendrologMenuItems() {
        String superOrGramatyk;
        if (identity.hasRole("superdendrolog")) {
            superOrGramatyk = "superdendrolog";
        } else
            superOrGramatyk = "gramatyk";
        statsDendrologMenuItems = new LinkedList<MenuItem>();
        statsDendrologMenuItems.add(new MenuItem("dendrolog", "statsDendrolog.seam", true));
        statsDendrologMenuItems.add(new MenuItem(superOrGramatyk, "statsSuperdendrolog.seam", false));
    }

    //@Factory(value = "userStats")
    //@Observer("tbpchangestate")
    public Stats generateUserStats() {
        this.getMyAllAnsNum();
        this.getMyAllDoneAnsNum();
        int total = (int) (long) myAllAnsNum;
        int done = (int) (long) myAllDoneAnsNum;
        userStats = new Stats(done, total);
        log.info("userStats = " + userStats);
        return userStats;
    }
}