'use strict'

/* @flow */

import FS from 'fs'
import URL from 'url'
import Path from 'path'
import {Emitter} from 'sb-event-kit'
import {promisedRequest, getRange} from './helpers'
import type {Disposable} from 'sb-event-kit'
import type {RangePool, PoolWorker} from 'range-pool'
import type {Readable} from 'stream'

export class Connection {
  emitter: Emitter;
  url: string;
  pool: RangePool;
  worker: PoolWorker;
  fileInfo: {
    size: number
  };
  response: Readable;

  constructor(url: string, pool: RangePool) {
    this.url = url
    this.pool = pool
  }
  async activate(): Promise {
    this.fileInfo = { size: 0 }
    this.worker = this.pool.createWorker()
    this.emitter = new Emitter()
    this.response = await promisedRequest({
      url: this.url,
      headers: {
        'User-Agent': 'sb-downloader for Node.js',
        'Range': getRange(this.worker)
      }
    })
    this.fileInfo.size = parseInt(this.response.headers['content-length']) || 0
  }
  start(fd: number) {
    this.response.on('data', chunk => {
      const chunkLength = chunk.length
      const remaining = this.worker.getRemaining()
      const shouldClose = remaining <= chunkLength

      if (chunkLength > remaining) {
        chunk = chunk.slice(0, remaining)
      }

      FS.write(fd, chunk, 0, chunk.length, this.worker.getCurrentIndex(), error => {
        if (error) {
          this.emitter.emit('did-error', error)
        }
      })
      this.worker.advance(chunk.length)
      this.emitter.emit('did-progress', this.worker.getCompletionPercentage())
      if (shouldClose) {
        this.emitter.emit('did-close')
        this.dispose()
      }
    })
    this.response.resume()
  }
  getResponse(): Object {
    return this.response
  }
  getFileSize(): number {
    return this.fileInfo.size
  }
  getFileName(): string {
    const parsed = URL.parse(this.url, true)
    return Path.basename(parsed.pathname || '')
  }
  onDidClose(callback: Function): Disposable {
    return this.emitter.on('did-close', callback)
  }
  onDidProgress(callback: Function): Disposable {
    return this.emitter.on('did-progress', callback)
  }
  onDidError(callback: Function): Disposable {
    return this.emitter.on('did-error', callback)
  }
  dispose() {
    this.emitter.dispose()
    this.worker.dispose()
    if (this.response) {
      // $FlowIgnore: It's an internal function for readable streams, but exposed by request API
      this.response.destroy()
    }
  }
}

@@ -471,16 +471,36 @@
 eadable;
+%0A  started: boolean;
 %0A%0A  cons
@@ -585,39 +585,179 @@
 l%0A  
-%7D%0A  async activate(): Promise %7B
+  this.started = false%0A    this.emitter = new Emitter()%0A  %7D%0A  async activate(): Promise%3CConnection%3E %7B%0A    if (this.started) %7B%0A      return ;%0A    %7D%0A%0A    this.started = true
 %0A   
@@ -832,41 +832,8 @@
 r()%0A
-    this.emitter = new Emitter()%0A
     
@@ -1095,16 +1095,32 @@
 %5D) %7C%7C 0%0A
+    return this%0A
   %7D%0A  st
@@ -2604,14 +2604,72 @@
 )%0A    %7D%0A
+    this.started = false%0A    this.emitter = new Emitter()%0A
   %7D%0A%7D%0A

Enhance flow of connection a bit