/* eslint-disable no-param-reassign */
/* eslint-disable max-classes-per-file */

'use strict';

const { EventEmitter } = require('events');

class Node {
    constructor(value) {
        this.value = value;
        this.next = null;
    }

    link(next) {
        this.next = next;
        next.prev = this;
        return this;
    }
}

module.exports = class List extends EventEmitter {
    constructor() {
        super();
        this.start = null;
        this.tail = null;
    }

    add(obj) {
        const node = new Node(obj);
        if (this.start) {
            this.start = node.link(this.start);
        } else {
            this.start = node;
            this.tail = node;
        }
        return node;
    }

    iterate(fn) {
        if (!this.start) {
            return;
        }
        let cursor = this.start;
        while (cursor) {
            const result = fn(cursor);
            if (result === false) {
                cursor = null;
            } else {
                cursor = cursor.next;
            }
        }
    }

    iterateReverse(fn) {
        if (!this.tail) {
            return;
        }
        let cursor = this.tail;
        while (cursor) {
            const result = fn(cursor);
            if (result === false) {
                cursor = null;
            } else {
                cursor = cursor.prev;
            }
        }
    }

    reverseRemoveUntilTrue(fn) {
        if (!this.tail) {
            return;
        }

        let cursor = this.tail;
        while (cursor) {
            const result = fn(cursor);
            if (result === false && cursor === this.start) {
                // whole list is removed
                this.emit('evicted', cursor.value);
                this.start = null;
                this.tail = null;
                // stop iteration
                cursor = null;
            } else if (result === true) {
                // when TRUE, set match as new tail
                if (cursor !== this.tail) {
                    this.tail = cursor;
                    cursor.next = null;
                }
                // stop iteration
                cursor = null;
            } else {
                // evicted
                this.emit('evicted', cursor.value);
                // iterate to next
                cursor = cursor.prev;
            }
        }
    }

    toArray() {
        const result = [];

        if (this.start) {
            let cursor = this.start;
            while (cursor) {
                result.push(cursor.value);
                cursor = cursor.next;
            }
        }

        return result;
    }

    // toArrayReverse () {
    //     const result = [];

    //     if (this.tail) {
    //         let cursor = this.tail;
    //         while (cursor) {
    //             result.push(cursor.value);
    //             cursor = cursor.prev;
    //         }
    //     }

    //     return result;
    // }
};
