# Copyright (C) 2016 ycmd contributors
#
# This file is part of ycmd.
#
# ycmd is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ycmd is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ycmd.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
from future import standard_library
standard_library.install_aliases()
from builtins import *  # noqa
from future.utils import native

from base64 import b64decode, b64encode
from hamcrest import assert_that, empty, equal_to, is_in
from tempfile import NamedTemporaryFile
import functools
import json
import os
import psutil
import re
import requests
import subprocess
import sys
import time
import urllib.parse

from ycmd.hmac_utils import CreateHmac, CreateRequestHmac, SecureBytesEqual
from ycmd.tests import PathToTestFile
from ycmd.tests.test_utils import BuildRequest
from ycmd.user_options_store import DefaultOptions
from ycmd.utils import ( GetUnusedLocalhostPort, PathToCreatedTempDir, ReadFile,
                         RemoveIfExists, SafePopen, SetEnviron, ToBytes,
                         ToUnicode )

HEADERS = { 'content-type': 'application/json' }
HMAC_HEADER = 'x-ycm-hmac'
HMAC_SECRET_LENGTH = 16
DIR_OF_THIS_SCRIPT = os.path.dirname( os.path.abspath( __file__ ) )
PATH_TO_YCMD = os.path.join( DIR_OF_THIS_SCRIPT, '..' )


class Client_test( object ):

  def __init__( self ):
    self._location = None
    self._port = None
    self._hmac_secret = None
    self._servers = []
    self._logfiles = []
    self._options_dict = DefaultOptions()


  def setUp( self ):
    self._hmac_secret = os.urandom( HMAC_SECRET_LENGTH )
    self._options_dict[ 'hmac_secret' ] = ToUnicode(
      b64encode( self._hmac_secret ) )


  def tearDown( self ):
    for server in self._servers:
      if server.is_running():
        server.terminate()
    for logfile in self._logfiles:
      RemoveIfExists( logfile )


  def Start( self, idle_suicide_seconds = 60,
             check_interval_seconds = 60 * 10 ):
    # The temp options file is deleted by ycmd during startup
    with NamedTemporaryFile( mode = 'w+', delete = False ) as options_file:
      json.dump( self._options_dict, options_file )
      options_file.flush()
      self._port = GetUnusedLocalhostPort()
      self._location = 'http://127.0.0.1:' + str( self._port )

      # Define environment variable to enable subprocesses coverage. See:
      # http://coverage.readthedocs.org/en/coverage-4.0.3/subprocess.html
      env = os.environ.copy()
      SetEnviron( env, 'COVERAGE_PROCESS_START', '.coveragerc' )

      ycmd_args = [
        sys.executable,