const { spawn } = require('child_process')
const { AutoLanguageClient } = require('atom-languageclient')
const DatatipAdapter = require('../node_modules/atom-languageclient/build/lib/adapters/datatip-adapter')
const CodeFormatAdapter = require('../node_modules/atom-languageclient/build/lib/adapters/code-format-adapter')
const Utils = require('../node_modules/atom-languageclient/build/lib/utils')
const path = require('path')
const { shell } = require('electron')
const { EventEmitter } = require('events')
const pkg = require('../package.json')
const { install } = require('atom-package-deps')

class GoDatatipAddapter extends DatatipAdapter {
    async getDatatip(connection, editor, point) {
        let res = await super.getDatatip(connection, editor, point)
        if (res) {
            res.range = Utils.getWordAtPosition(editor, point)
        }
        return res
    }
}

class GoLanguageClient extends AutoLanguageClient {
    constructor() {
        super()
        this.datatip = new GoDatatipAddapter()
        this.emitter = new EventEmitter()
        this.config = {
            customServerPath: {
                description: `Custom path to ${this.getServerName()}`,
                type: 'string',
                default: this.getServerName(),
                order: 1
            },
            completionEnabled: {
                description: 'Enable code completion (requires restart)',
                type: 'boolean',
                default: true,
                order: 2
            }
        }
    }

    getGrammarScopes() {
        return pkg['enhancedScopes']
    }
    getLanguageName() {
        return 'Go'
    }
    getServerName() {
        return 'go-langserver'
    }

    async startServerProcess() {
        await install(pkg['name'])

        const args = [];
        if (atom.config.get(`${pkg['name']}.completionEnabled`)) {
          args.push('-gocodecompletion');
        }

        const childProcess = spawn(await this.serverPath(), args, {
            cwd: path.join(__dirname, '..'),
            env: process.env
        })
        this.captureServerErrors(childProcess)
        childProcess.on('exit', this.onExit)
        return childProcess
    }

    consumeGoGet(goGet) {
        this.goGet = goGet
        if (this.goConfig) {
            this.emitter.emit('go-ready')
        }
    }

    consumeGoConfig(goConfig) {
        this.goConfig = goConfig
        if (this.goGet) {
            this.emitter.emit('go-ready')
        }
    }

    goReady() {
        return new Promise(resolve => {
            if (this.goConfig && this.goGet) {
                return resolve()
            }
            this.emitter.on('go-ready', resolve)
        })
    }

    async serverPath() {
        let customPath = atom.config.get(`${pkg['name']}.customServerPath`)
        if (customPath !== this.config.customServerPath.default) {
            return customPath
        }
        await this.goReady()
        let serverPath = await this.goConfig.locator.findTool(
            this.getServerName()
        )
        if (serverPath) {
            return serverPath
        }
        await this.goGet.get({
            name: pkg['name'],
            packageName: this.getServerName(),
            packagePath: 'github.com/sourcegraph/go-langserver/',
            type: 'missing'
        })
        return await this.goConfig.locator.findTool(this.getServerName())
    }

    handleSpawnFailure(err) {
        atom.notifications.addError(
            `Unable to start the ${this.getLanguageName()} language server.`,
            {
                dismissable: true,
                buttons: [
                    {
                        text: `Download ${this.getServerName()}`,
                        onDidClick: () =>
                            shell.openExternal(
                                'https://github.com/sourcegraph/go-langserver/blob/master/README.md'
                            )
                    }
                ],
                description: err.toString()
            }
        )
    }

    onExit(code, signal) {
        if (code) {
            atom.notifications.addError(
                `${this.getLanguageName()} language server stopped unexpectedly.`,
                {
                    dismissable: true,
                    description: `Exit code: ${code}\n${this.processStdErr}`
                }
            )
        }
    }

    provideFileCodeFormat() {
        return {
            grammarScopes: this.getGrammarScopes(),
            priority: 1,
            formatEntireFile: this.getFileCodeFormat.bind(this)
        }
    }

    async getFileCodeFormat(editor) {
        const server = await this._serverManager.getServer(editor)
        if (
            server == null ||
            !CodeFormatAdapter.canAdapt(server.capabilities)
        ) {
            return []
        }
        //HACK: get the first non empty 'newText'.
        return Promise.resolve({
            formatted: (await CodeFormatAdapter.formatDocument(
                server.connection,
                editor
            )).reduce((accu, elem) => {
                return accu || elem['newText'] || ''
            })
        })
    }
}

module.exports = new GoLanguageClient()

@@ -1497,16 +1497,207 @@
 rder: 2%0A
+            %7D,%0A            pprofAddr: %7B%0A                description: 'pprof address (requires restart)',%0A                type: 'string',%0A                default: '',%0A                order: 3%0A
         
@@ -1694,32 +1694,32 @@
 3%0A            %7D%0A
-
         %7D%0A    %7D%0A
@@ -1989,17 +1989,16 @@
 rgs = %5B%5D
-;
 %0A       
@@ -2010,36 +2010,16 @@
 atom
-.c
+C
 onfig
-.get(%60$%7Bpkg%5B'name'%5D%7D.
+('
 comp
@@ -2035,14 +2035,16 @@
 bled
-%60
+'
 )) %7B%0A
+  
     
@@ -2083,9 +2083,117 @@
 on')
-;
+%0A        %7D%0A%0A        if (atomConfig('pprofAddr')) %7B%0A            args.push(%60-pprof=$%7BatomConfig('pprofAddr')%7D%60)
 %0A   
@@ -3046,36 +3046,16 @@
 atom
-.c
+C
 onfig
-.get(%60$%7Bpkg%5B'name'%5D%7D.
+('
 cust
@@ -3066,17 +3066,17 @@
 rverPath
-%60
+'
 )%0A      
@@ -5464,16 +5464,98 @@
    %7D%0A%7D%0A%0A
+function atomConfig(key) %7B%0A    return atom.config.get(%60$%7Bpkg%5B'name'%5D%7D.$%7Bkey%7D%60)%0A%7D%0A%0A
 module.e

Add pprof option (#16)