/* global AUDIO_BASE */

const AHEAD_SIZE = 60;

import splits from './splits';
import { format } from './audio';

let last_floor_index = 0;

export default class AudioChunks {
    constructor(stem) {
        this.stem = stem;
        this.chunks = splits(stem).formats[format.suffix];
        if (!this.chunks) {
            throw 'no chunks for stem "' + stem + '" and format "' + format + '"';
        }
        this.ensured_for_min = -1;
        this.ensured_for_max = -2;
    }

    get_floor_chunk(pos) {
        const me = this;
        let floor_chunk;
        let floor_index;
        const start = me.chunks[last_floor_index].from < pos ? last_floor_index : 0;
        for (let i = start; i < me.chunks.length; i++) {
            const chunk = me.chunks[i];
            if (chunk.from <= pos) {
                floor_chunk = chunk;
                floor_index = i;
            }
            else {
                break;
            }
        }
        if (!floor_chunk) {
            throw "could not find floor chunk for stem " + me.stem + ", position " + pos;
        }
        last_floor_index = floor_index;
        return { floor_index, floor_chunk };
    }

    load_from_pos(pos) {
        const me = this;
        return new Promise((fulfill, reject) => {
            const { floor_chunk, floor_index } = me.get_floor_chunk(pos);
            let containing_chunk;

            if (floor_chunk && floor_chunk.to > pos) {
                containing_chunk = floor_chunk;
            }
            else {
                throw "could not find containing chunk for stem " + me.stem + ", position " + pos;
            }
            me.get_chunk_promise(containing_chunk).catch(reject).then(fulfill);
        });
    }

    get_chunk_promise(chunk) {
        const me = this;
        if (chunk.promise) {
            return chunk.promise;
        }
        else {
            return me.load_chunk(chunk);
        }
    }

    load_chunk(chunk) {
        const me = this;
        chunk.promise = new Promise((fulfill, reject) => {
            me.get_chunk_ea_promise(chunk).then(encoded_audio => {
                new AudioContext().decodeAudioData(encoded_audio, decoded_buffer => {
                    chunk.buffer = decoded_buffer;
                    fulfill(decoded_buffer);
                });
            });
        });
        return chunk.promise;
    }

    get_chunk_ea_promise(chunk) { // ea = encoded audio
        const me = this;
        if (chunk.ea_promise) {
            return chunk.ea_promise;
        }
        else {
            return me.load_chunk_ea(chunk);
        }
    }

    load_chunk_ea(chunk) {
        const me = this;
        chunk.url = AUDIO_BASE + 'splits/' + chunk.basename;
        chunk.ea_promise = new Promise((fulfill, reject) => {
            fetch(chunk.url).then(res => {
                res.arrayBuffer().then(encoded_audio => {
                    // chunk.encoded_audio = encoded_audio;
                    fulfill(encoded_audio);
                }).catch(reject);
            }).catch(reject);
        });
        return chunk.ea_promise;
    }

    get_ahead_window(pos, requested) {
        const me = this;
        if (!(({ promise: true, buffer: true, audio_source: true })[requested])) {
            throw 'unexpected ahead window attribute ' + requested;
        }
        const { floor_chunk, floor_index } = me.get_floor_chunk(pos);
        if (!floor_chunk[requested]) {
            return [];
        }
        let ceil_index;
        for (let i = floor_index; me.chunks[i][requested]; i++) {
            ceil_index = i;
        }
        return me.chunks.slice(floor_index, ceil_index + 1);
    }

    ensure_ahead_window(pos, len = AHEAD_SIZE) {
        const me = this;
        if (pos >= me.ensured_for_min && pos <= me.ensured_for_max) {
            return [];
        }
        /*
        const ahead_window = me.get_ahead_window(pos, 'promise');
        if (ahead_window.len >= len) {
            return;
        }
        */
        let { floor_index, floor_chunk } = me.get_floor_chunk(pos);

        let i = floor_index;
        let c = floor_chunk;
        const target_pos = pos + len;
        let reached_pos = -2;
        let newly_loaded_chunks = [];
        while (reached_pos < target_pos && i < me.chunks.length) {
            if (!c.promise) {
                me.get_chunk_promise(c);
                newly_loaded_chunks.push(c);
            }
            reached_pos = c.to;
            i++;
            c = me.chunks[i];
        }

        me.ensured_for_min = floor_chunk.from;
        me.ensured_for_max = reached_pos - len;
        return newly_loaded_chunks;
    }
}

@@ -1172,565 +1172,8 @@
  %7D%0A%0A
-    load_from_pos(pos) %7B%0A        const me = this;%0A        return new Promise((fulfill, reject) =%3E %7B%0A            const %7B floor_chunk, floor_index %7D = me.get_floor_chunk(pos);%0A            let containing_chunk;%0A%0A            if (floor_chunk && floor_chunk.to %3E pos) %7B%0A                containing_chunk = floor_chunk;%0A            %7D%0A            else %7B%0A                throw %22could not find containing chunk for stem %22 + me.stem + %22, position %22 + pos;%0A            %7D%0A            me.get_chunk_promise(containing_chunk).catch(reject).then(fulfill);%0A        %7D);%0A    %7D%0A%0A
     

remove unused audiochunks method