import os
import ycm_core

# You can set a directory with a lot of libraries to be search recursively here
ArduinoLibDir = ["/Applications/Arduino.app/Contents/Resources/Java/libraries", "/Applications/Arduino.app/Contents/Java/libraries"]

# This is the list of all directories to search for header files
libDirs = ArduinoLibDir + ["lib"]

flags = [
  # General flags
  '-Wall'
  ,'-Wextra'
  ,'-Werror'

  ,'-Wno-attributes'
  ,'-std=c++11'
  ,'-x'
  ,'c++'

  # Avr-libc flags for 1.8.0 and 1.8.1 installed with homebrew
  # You can deleted the one you don't need
  ,'-isystem/usr/local/Cellar/avr-libc/1.8.0/avr/include'
  ,'-isystem/usr/local/Cellar/avr-libc/1.8.1/avr/include'

  # Arduino libs flags when downloaded from the arduino website
  # IDE 1.0.6
  ,'-I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino'
  ,'-I/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/variants/mega'
  # IDE 1.6.3
  ,'-I/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino'
  ,'-I/Applications/Arduino.app/Contents/Java/hardware/arduino/avr/variants/mega'

  # Arduino libs flags when installed with brew cask or if the path is not the regular one
  # Beware, the version number can change
  # ,'-I/opt/homebrew-cask/Caskroom/arduino/1.0.6/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino'
  # ,'-I/opt/homebrew-cask/Caskroom/arduino/1.0.6/Arduino.app/Contents/Resources/Java/hardware/arduino/variants/mega'

  # You can add custom libraries here, but note that the script will automatically scan the 'lib' directory.
  ,'-I./lib/MyFirstLib'

  # Customize microcontroler and Arduino version
  ,'-mmcu=atmega2560'
  ,'-DF_CPU=16000000L'
  ,'-DARDUINO=105'
  ,'-D__AVR__'
  ,'-D__AVR_ATmega2560__'

  # ,'-MMD -DUSB_VID=null'
  # ,'-DUSB_PID=null'
]


compilation_database_folder = ''

if os.path.exists( compilation_database_folder ):
  database = ycm_core.CompilationDatabase( compilation_database_folder )
else:
  database = None

SOURCE_EXTENSIONS = [ '.cpp', '.cxx', '.cc', '.c', '.ino', '.m', '.mm' ]

def DirectoryOfThisScript():
  return os.path.dirname( os.path.abspath( __file__ ) )

def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
  if not working_directory:
    return list( flags )

  new_flags = []
  make_next_absolute = False
  path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]

  for libDir in libDirs:
    for path, dirs, files in os.walk(libDir):
      for d in dirs:
        flag = '-I' + os.path.join(path, d)
        flags.append(flag)

  for flag in flags:
    new_flag = flag

    if make_next_absolute:
      make_next_absolute = False
      if not flag.startswith( '/' ):
        new_flag = os.path.join( working_directory, flag )

    for path_flag in path_flags:
      if flag == path_flag:
        make_next_absolute = True
        break

      if flag.startswith( path_flag ):
        path = flag[ len( path_flag ): ]
        new_flag = path_flag + os.path.join( working_directory, path )
        break

    if new_flag:
      new_flags.append( new_flag )
  return new_flags


def IsHeaderFile( filename ):
  extension = os.path.splitext( filename )[ 1 ]
  return extension in [ '.h', '.hxx', '.hpp', '.hh' ]


def GetCompilationInfoForFile( filename ):
  # The compilation_commands.json file generated by CMake does not have entries
  # for header files. So we do our best by asking the db for flags for a
  # corresponding source file, if any. If one exists, the flags for that file
  # should be good enough.
  if IsHeaderFile( filename ):
    basename = os.path.splitext( filename )[ 0 ]
    for extension in SOURCE_EXTENSIONS:
      replacement_file = basename + extension
      if os.path.exists( replacement_file ):
        compilation_info = database.GetCompilationInfoForFile(
          replacement_file )
        if compilation_info.compiler_flags_:
          return compilation_info
    return None
  return database.GetCompilationInfoForFile( filename )


def FlagsForFile( filename, **kwargs ):
  if database:
    # Bear in mind that compilation_info.compiler_flags_ does NOT return a
    # python list, but a "list-like" StringVec object
    compilation_info = GetCompilationInfoForFile( filename )
    if not compilation_info:
      return None

    final_flags = MakeRelativePathsInFlagsAbsolute(
      compilation_info.compiler_flags_,
      compilation_info.compiler_working_dir_ )

    # NOTE: This is just for YouCompleteMe; it's highly likely that your project
    # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
    # ycm_extra_conf IF YOU'RE NOT 100% SURE YOU NEED IT.
    #try:
    #  final_flags.remove( '-stdlib=libc++' )
    #except ValueError:
    #  pass
  else:
    relative_to = DirectoryOfThisScript()
    final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )

  return {
    'flags': final_flags,
    'do_cache': True
  }

@@ -117,16 +117,19 @@
 bDir = %5B
+%0A  
 %22/Applic
@@ -181,18 +181,75 @@
 braries%22
+%0A  ,%22/Applications/Arduino.app/Contents/Java/libraries%22%0A  
 ,
- 
 %22/Applic
@@ -273,32 +273,53 @@
 p/Contents/Java/
+hardware/arduino/avr/
 libraries%22%5D%0A%0A# T
@@ -312,16 +312,17 @@
 braries%22
+%0A
 %5D%0A%0A# Thi
@@ -1809,10 +1809,10 @@
 NO=1
-05
+63
 '%0A  
@@ -3126,24 +3126,24 @@
 f new_flag:%0A
-
       new_fl
@@ -3165,16 +3165,17 @@
 _flag )%0A
+%0A
   return

update YCM config file to be used with Arduino 1.6.3