/********************************************************************
 SleepLib Day Class Implementation
 Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net>
 License: GPL
*********************************************************************/

#include "day.h"

Day::Day(Machine *m)
:machine(m)
{
    d_firstsession=true;
}
Day::~Day()
{
    vector<Session *>::iterator s;
    for (s=sessions.begin();s!=sessions.end();s++) {
        delete (*s);
    }

}
MachineType Day::machine_type()
{
    return machine->GetType();
};

void Day::AddSession(Session *s)
{
    if (!s) {
        qWarning("Day::AddSession called with NULL session object");
        return;
    }
    if (d_firstsession) {
        d_firstsession=false;
        d_first=s->first();
        d_last=s->last();
    } else {
        if (d_first > s->first()) d_first = s->first();
        if (d_last < s->last()) d_last = s->last();
    }
    sessions.push_back(s);
}

EventDataType Day::summary_sum(MachineCode code)
{
    EventDataType val=0;
    vector<Session *>::iterator s;
    for (s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.summary.find(code)!=sess.summary.end()) {
            val+=sess.summary[code].toDouble();
        }
    }
    return val;
}

EventDataType Day::summary_max(MachineCode code)
{
    EventDataType val=0,tmp;

    vector<Session *>::iterator s;
    for (s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.summary.find(code)!=sess.summary.end()) {
            tmp=sess.summary[code].toDouble();
            if (tmp>val) val=tmp;
        }
    }
    return val;
}
EventDataType Day::summary_min(MachineCode code)
{
    EventDataType val=0,tmp;
    bool fir=true;
    // Cache this?

    vector<Session *>::iterator s;
    for (s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.summary.find(code)!=sess.summary.end()) {
            tmp=sess.summary[code].toDouble();
            if (fir) {
                val=tmp;
                fir=false;
            } else {
                if (val<tmp) val=tmp;
            }
        }
    }
    return val;
}

EventDataType Day::summary_avg(MachineCode code)
{
    EventDataType val=0,tmp=0;

    int cnt=0;
    vector<Session *>::iterator s;
    for (s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.summary.find(code)!=sess.summary.end()) {
            tmp+=sess.summary[code].toDouble();
            cnt++;
        }
    }
    val=tmp/EventDataType(cnt);
    return val;
}
EventDataType Day::summary_weighted_avg(MachineCode code)
{
    double s0=0,s1=0,s2=0;
    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.summary.find(code)!=sess.summary.end()) {
            s0=sess.hours();
            s1+=sess.summary[code].toDouble()*s0;
            s2+=s0;
        }
    }
    if (s2==0) return 0;
    return (s1/s2);

}

EventDataType Day::avg(MachineCode code)
{
    double val=0;
    // Cache this?
    int cnt=0;
    vector<Session *>::iterator s;

    // Don't assume sessions are in order.
    for (s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.eventlist.find(code)!=sess.eventlist.end()) {
            val+=sess.avg(code);
            cnt++;
        }
    }
    if (cnt==0) return 0;
    return EventDataType(val/float(cnt));
}

EventDataType Day::sum(MachineCode code)
{
    // Cache this?
    EventDataType val=0;
    vector<Session *>::iterator s;

    for (s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.eventlist.find(code)!=sess.eventlist.end()) {
            val+=sess.sum(code);
        }
    }
    return val;
}

EventDataType Day::weighted_avg(MachineCode code)
{
    double s0=0,s1=0,s2=0;
    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.eventlist.find(code)!=sess.eventlist.end()) {
            s0=sess.hours();
            s1+=sess.weighted_avg(code)*s0;
            s2+=s0;
        }
    }
    if (s2==0) return 0;
    return (s1/s2);
}
// Total session time in milliseconds
qint64 Day::total_time()
{
    qint64 d_totaltime=0;
    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        d_totaltime+=sess.last()-sess.first();
    }
    return d_totaltime;
}
EventDataType Day::percentile(MachineCode code,double percent)
{
    double val=0;
    int cnt=0;

    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        Session & sess=*(*s);
        if (sess.eventlist.find(code)!=sess.eventlist.end()) {
            val+=sess.percentile(code,percent);
            cnt++;
        }
    }
    if (cnt==0) return 0;
    return EventDataType(val/cnt);

}

qint64 Day::first(MachineCode code)
{
    qint64 date=0;
    qint64 tmp;

    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        tmp=(*s)->first(code);
        if (!tmp) continue;
        if (!date) {
            date=tmp;
        } else {
            if (tmp<date) date=tmp;
        }
    }
    return date;
}

qint64 Day::last(MachineCode code)
{
    qint64 date=0;
    qint64 tmp;

    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        tmp=(*s)->last(code);
        if (!tmp) continue;
        if (!date) {
            date=tmp;
        } else {
            if (tmp>date) date=tmp;
        }
    }
    return date;
}
EventDataType Day::min(MachineCode code)
{
    EventDataType min=0;
    EventDataType tmp;
    bool first=true;
    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        if ((*s)->eventlist.find(code)==(*s)->eventlist.end()) continue;
        tmp=(*s)->min(code);
        if (first) {
            min=tmp;
            first=false;
        } else {
            if (tmp<min) min=tmp;
        }
    }
    return min;
}

EventDataType Day::max(MachineCode code)
{
    EventDataType max=0;
    EventDataType tmp;
    bool first=true;
    for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
        if ((*s)->eventlist.find(code)==(*s)->eventlist.end()) continue;
        tmp=(*s)->max(code);
        if (first) {
            max=tmp;
            first=false;
        } else {
            if (tmp>max) max=tmp;
        }
    }
    return max;
}
int Day::count(MachineCode code)
{
    int sum=0;
    for (unsigned i=0;i<sessions.size();i++) {
        sum+=sessions[i]->count(code);
    }
    return sum;
}
void Day::OpenEvents()
{
    vector<Session *>::iterator s;

    for (s=sessions.begin();s!=sessions.end();s++) {
        (*s)->OpenEvents();
    }

}