const _readline = require('readline');

// low-level terminal interactions
class Terminal{

    constructor(outputStream){
        this.stream = outputStream;

        // default: line wrapping enabled
        this.linewrap = true;

        // current, relative y position
        this.dy = 0;
    }

    // save cursor position + settings
    cursorSave(){
        if (!this.stream.isTTY){
            return;
        }

        // save position
        this.stream.write('\x1B7');
    }

    // restore last cursor position + settings
    cursorRestore(){
        if (!this.stream.isTTY){
            return;
        }

        // restore cursor
        this.stream.write('\x1B8');
    }

    // show/hide cursor
    cursor(enabled){
        if (!this.stream.isTTY){
            return;
        }

        if (enabled){
            this.stream.write('\x1B[?25h');
        }else{
            this.stream.write('\x1B[?25l');
        }
    }

    // change cursor positionn
    cursorTo(x=null, y=null){
        if (!this.stream.isTTY){
            return;
        }

        // move cursor absolute
        _readline.cursorTo(this.stream, x, y);
    }

    // change relative cursor position
    cursorRelative(dx=null, dy=null){
        if (!this.stream.isTTY){
            return;
        }

        // store current position
        this.dy = this.dy + dy;
        
        // move cursor relative
        _readline.moveCursor(this.stream, dx, dy);
    }

    // relative reset
    cursorRelativeReset(){
        if (!this.stream.isTTY){
            return;
        }

        // move cursor to initial line
        _readline.moveCursor(this.stream, 0, -this.dy);

        // first char
        _readline.cursorTo(this.stream, 0, null);

        // reset counter
        this.dy = 0;
    }

    // clear to the right from cursor
    clearRight(){
        if (!this.stream.isTTY){
            return;
        }

        _readline.clearLine(this.stream, 1);
    }

    // clear the full line
    clearLine(){
        if (!this.stream.isTTY){
            return;
        }

        _readline.clearLine(this.stream, 0);
    }

    // clear everyting beyond the current line
    clearBottom(){
        if (!this.stream.isTTY){
            return;
        }

        _readline.clearScreenDown(this.stream);
    }

    // add new line; increment counter
    newline(){
        this.stream.write('\n');
        this.dy++;
    }

    // write content to output stream
    // @TODO use string-width to strip length
    write(s, rawWrite=false){
        // line wrapping enabled ? trim output
        // this is just a fallback mechanism in case user enabled line-wrapping via options or set it to auto
        if (this.linewrap === true && rawWrite === false){
            this.stream.write(s.substr(0, this.getWidth()));

        // standard behaviour with disabled linewrapping
        }else{
            this.stream.write(s);
        }
    }

    // control line wrapping
    lineWrapping(enabled){
        if (!this.stream.isTTY){
            return;
        }

        // store state
        this.linewrap = enabled;
        if (enabled){
            this.stream.write('\x1B[?7h');
        }else{
            this.stream.write('\x1B[?7l');
        }
    }

    // tty environment ?
    isTTY(){
        return (this.stream.isTTY === true);
    }

    // get terminal width
    getWidth(){
        // set max width to 80 in tty-mode and 200 in notty-mode
        return this.stream.columns || (this.stream.isTTY ? 80 : 200);
    }
}

module.exports = Terminal;
