import {SleepStages, EventIds} from './AuroraConstants';

export default class AuroraSessionParser {

    static parseSessionTxtObject = (sessionTxtObject) => {

        const session = {
            awakenings: 0,
            sleepOnset: 0,
            incomplete: false,
            awakeAt: 0,
            asleepAt: 0,
            sleepScore: 0,
            sleepDuration: {
                total: 0,
                unknown: 0,
                awake: 0,
                light: 0,
                deep: 0,
                rem: 0
            }
        };

        const throwError = (error) => {

            session.error = error;
            return Promise.reject(session);
        };

        if (typeof sessionTxtObject != 'object') return throwError('Session object invalid.');

        //TODO: consider using deep assign
        Object.assign(session, sessionTxtObject);

        if (!session.version || !session.date || !session.profile || !session.duration) return throwError('Session corrupted.');

        if (parseInt(session.version) < 20001) return throwError('Aurora firmware version no longer supported.');

        if (!Array.isArray(session.events) || !session.events.length) return throwError('This session has no events.');

        if (session.duration < 1000 * 60 * 30) return throwError('Session is shorter than 30 minutes.');

        let signalPresent = false;

        for (const event of session.events) {

            if (typeof event.id == 'undefined' || typeof event.time == 'undefined' || typeof event.flags == 'undefined') {

                return throwError('One or more session events are corrupted.');
            }

            if (event.id == EventIds.SLEEP_TRACKER_MONITOR && event.flags != SleepStages.UNKNOWN) {

                signalPresent = true;
            }

            event.date = session.date + event.time;
        }

        if (!signalPresent) return throwError('Session does not contain a clean EEG signal.');

        if (session.streams) {

            if (!Array.isArray(session.streams)) return throwError('Session stream array corrupted.');

            for (const stream of session.streams) {

                if (typeof stream.id == 'undefined' || typeof stream.time == 'undefined' || typeof stream.type == 'undefined' || !stream.file) {

                    return throwError('One or more session streams are corrupted.');
                }

                stream.date = session.date + stream.time;
            }
        }

        let firstSignalStageTime = 0;
        let currentStage = 0;
        let currentStageTime = 0;

        const stageDurations = new Array(Object.keys(SleepStages).length).fill(0);

        for (const event of session.events) {

            switch (event.id) {

                case EventIds.SLEEP_TRACKER_MONITOR:

                    const stage = event.flags;

                    if (!firstSignalStageTime && stage > SleepStages.UNKNOWN) {

                        firstSignalStageTime = event.time;
                    }

                    if (currentStageTime) {

                        stageDurations[currentStage] += (event.time - currentStageTime);
                    }

                    //is this a non-awake stage?
                    if (stage > SleepStages.AWAKE) {

                        //is this the first non-awake sleep stage?
                        if (!session.asleepAt) {

                            session.asleepAt = event.date;
                            session.sleepOnset = event.time - firstSignalStageTime;
                        }
                    }
                    //is this an awake stage and have we found the first sleep event?
                    else if (stage == SleepStages.AWAKE && session.asleepAt) {

                        session.awakeAt = event.date;
                    }

                    //update current stage/time
                    currentStage = stage;
                    currentStageTime = event.time;

                    break;

                case EventIds.AUTO_SHUTDOWN:

                    session.incomplete = true;

                    break;

                case EventIds.AWAKENING:

                    session.awakenings++;

                    break;
            }
        }

        session.sleepDuration.total = stageDurations.reduce((p, c) => p + c);
        session.sleepDuration.unknown = stageDurations[SleepStages.UNKNOWN];
        session.sleepDuration.awake = stageDurations[SleepStages.AWAKE];
        session.sleepDuration.light = stageDurations[SleepStages.LIGHT];
        session.sleepDuration.deep = stageDurations[SleepStages.DEEP];
        session.sleepDuration.rem = stageDurations[SleepStages.REM];

        if (session.sleepDuration.total) {

            session.sleepScore = Math.floor((session.sleepDuration.deep + session.sleepDuration.rem) / session.sleepDuration.total * 200);
        }

        return Promise.resolve(session);
    };

};


@@ -530,32 +530,81 @@
  0%0A            %7D
+,%0A            events: %5B%5D,%0A            streams: %5B%5D
 %0A        %7D;%0A%0A   
@@ -1213,34 +1213,107 @@
 nts)
- %7C%7C !s
+) return throwError('S
 ession
-.
+ 
 event
-s.length
+ array corrupted.');%0A%0A        if (!Array.isArray(session.streams)
 ) re
@@ -1333,34 +1333,38 @@
 or('
-This s
+S
 ession 
-has no events
+stream array corrupted
 .');
@@ -1364,33 +1364,34 @@
 ted.');%0A%0A       
- 
+//
 if (session.dura
@@ -1476,44 +1476,8 @@
 );%0A%0A
-        let signalPresent = false;%0A%0A
     
@@ -1754,443 +1754,89 @@
     
-if (event.id == EventIds.SLEEP_TRACKER_MONITOR && event.flags != SleepStages.UNKNOWN) %7B%0A%0A                signalPresent = true;%0A            %7D%0A%0A            event.date = session.date + event.time;%0A        %7D%0A%0A        if (!signalPresent) return throwError('Session does not contain a clean EEG signal.');%0A%0A        if (session.streams) %7B%0A%0A            if (!Array.isArray(session.streams)) return throwError('Session stream array corrupted.');
+event.date = session.date + event.time;%0A        %7D%0A%0A        if (session.streams) %7B
 %0A%0A  

Make session parsing less strict.