const fs = require('fs')
const path = require('path')
const EventEmitter = require('events')
let LinkList = require('./linkList')
class Queue {
constructor(){
this.LinkList = new LinkList()
}
offer(element){
this.LinkList.add(element)
}
poll(){
return this.LinkList.remove(0)
}
}
class WriteStream extends EventEmitter {
constructor(path,options){
super();
this.path = path;
this.flags = options.flags || 'w';
this.autoClose = options.autoClose || true;
this.encoding = options.encoding || 'utf8';
this.start = options.start || 0;
this.mode = options.mode || 0o666;
this.highWaterMark = options.highWaterMark || 16 * 1024
this.len = 0;
this.writing = false;
this.needDrain = false;
this.offset = this.start;
this.cache = new Queue();
this.open()
}
open() {
fs.open(this.path, this.flags,this.mode,(err,fd) => {
if(err) return this.emit('error',err);
this.fd = fd
this.emit('open',fd)
})
}
write(chunk,encoding = 'utf8',cb=()=>{}){
chunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
this.len += chunk.length
let flag = this.len < this.highWaterMark;
this.needDrain = !flag
if(this.writing){
this.cache.offer({
chunk,encoding,cb
})
}else{
this.writing = true
this._write(chunk,encoding,()=>{
cb()
this.clearBuffer()
})
}
return flag
}
_write(chunk,encoding,cb){
if(typeof this.fd !== 'number'){
return this.once('open',() => this._write(chunk,encoding,cb))
}
fs.write(this.fd,chunk,0,chunk.length,this.offset,(err,writen) => {
this.len -= writen
this.offset += writen
cb()
})
}
clearBuffer(){
let data = this.cache.poll()
if(data){
let {chunk,encoding,cb} = data
this._write(chunk,encoding,() =>{
cb()
this.clearBuffer()
})
}else{
this.writing = false
if(this.needDrain){
this.needDrain = false
this.emit('drian')
}
}
}
}