#!/usr/bin/env python

import os, sys, fnmatch
from subprocess import call
import json
import re

arduino_ide_path = os.environ['ARDUINO_IDE_PATH']
energia_ide_path = os.environ['ENERGIA_IDE_PATH']

''' Arduino Board Manager URLs:
https://github.com/esp8266/Arduino/releases/download/2.4.0-rc2/package_esp8266com_index.json
https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json
https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
http://digistump.com/package_digistump_index.json
http://download.labs.mediatek.com/package_mtk_linkit_index.json
http://download.labs.mediatek.com/package_mtk_linkit_smart_7688_index.json
https://redbearlab.github.io/arduino/package_redbearlab_index.json
https://redbearlab.github.io/arduino/package_redbear_index.json
http://downloads.konekt.io/arduino/package_konekt_index.json
https://www.simblee.com/package_simblee_index.json
https://github.com/chipKIT32/chipKIT-core/raw/master/package_chipkit_index.json
http://rfduino.com/package_rfduino_index.json
https://github.com/wasdpkj/Microduino-IDE-Support/raw/master/package_Microduino_index.json
https://raw.githubusercontent.com/sparkfun/Arduino_Boards/master/IDE_Board_Manager/package_sparkfun_index.json
http://downloads.arduino.cc/packages/package_arduino.cc_linux_index.json
https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json
http://dan.drown.org/stm32duino/package_STM32duino_index.json
http://update.wickeddevice.com/package_WildFireBSP-4.0.0_index.json
'''

def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename

hardware = os.path.expanduser('~') + '/.arduino15/packages/'
boards = find_files(hardware, 'boards.txt')

hardware2 = arduino_ide_path + '/hardware/'
boards2 = find_files(hardware2, 'boards.txt')

hardware3 = os.path.expanduser('~') + '/.energia15/packages/'
boards3 = find_files(hardware3, 'boards.txt')

hardware4 = energia_ide_path + '/hardware/'
boards4 = find_files(hardware4, 'boards.txt')

boards = list(boards) + list(boards2) + list(boards3) + list(boards4)
boards = filter(lambda x: -1 == x.find('variants'), boards)

fqbns = []
for b in boards:
    folders = b.replace(hardware,'').replace(hardware2,'').replace(hardware3,'').replace(hardware4,'')
    folders = folders.split('/')
    if len(folders) == 3:
        fqbn = [ folders[i] for i in [0, 1] ]
    else:
        fqbn = [ folders[i] for i in [0, 2] ]

    lastname = "#"
    with open(b) as f:
        for line in f.readlines():
            if ".name=" in line:
                line=line.strip()
                names = line.split(".name=")
                if names[0].startswith('#'):
                    continue

                lastname = names[0]
                name = names[1]
                fqbns.append({
                    'name': name,
                    'fqbn': ':'.join(fqbn + [lastname])
                })
            elif line.startswith(lastname + ".menu."):
                line = line.split('.menu.')[1]
                line = line.split('=')[0]
                line = line.split('.')
                fbqn = fqbns[-1]
                if not "opts" in fbqn:
                    fbqn["opts"] = {}
                if not line[0] in fbqn["opts"]:
                    fbqn["opts"][line[0]] = line[1]

advanced_boards = {
  "attiny:avr:ATtinyX5" : ":cpu=attiny85,clock=internal16",
  "attiny:avr:ATtinyX4" : ":cpu=attiny84,clock=internal8",
}

for x in fqbns:
    if x['fqbn'] in advanced_boards.keys():
        x['fqbn_adv'] = x['fqbn'] + advanced_boards[x['fqbn']]
    elif 'opts' in x:
        opts = ""
        for o in x['opts'].keys():
            opts +=  o + '=' + x['opts'][o] + ','

        x['fqbn_adv'] = x['fqbn'] + ":" + opts.strip(',')

#print json.dumps(fqbns, sort_keys=True, indent=2)
#exit(0)

logfile = open("./build.log","wb")
datafile = os.path.abspath('./extras/all-boards.json')
fn = os.path.abspath('./tests/BlynkBuildTest/BlynkBuildTest.ino')

try:
    with open(datafile, 'r') as fp:
        json_data = json.load(fp)
except:
    json_data = {}
json_data.setdefault('failed', [])
json_data.setdefault('built', [])
json_data.setdefault('skip', [])
data = {
  'failed': set(json_data['failed']),
  'built': set(json_data['built']),
}

skip_boards = [
  # Hello world fails:
  "chipKIT:pic32:OpenScope",
  "chipKIT:pic32:openbci",
  "chipKIT:pic32:uno_pmod",
  "stm32duino:STM32F1:genericGD32F103C",
  "stm32duino:STM32F1:genericSTM32F103T",

  # __FlashString problem:
  "digistump:avr:digispark-tiny*",

  # No c++0x:
  "stm32duino:STM32F3:discovery_f3",
]

skip_boards = "(" + ")|(".join(skip_boards) + ")"

fqbns.sort(key=lambda x: x['fqbn'] in data['built'])

for m in fqbns:

    if len(sys.argv) > 1:
        if m['fqbn'] != sys.argv[1]:
            continue
    elif re.match(skip_boards, m['fqbn']):
        continue

    print "Building:", m['name'], " (", m['fqbn'], ")", " ...",
    sys.stdout.flush()

    print >>logfile, "\n\n", "================="
    print >>logfile, "Building:", m['name'], " (", m['fqbn'], ")"
    print >>logfile, "=================", "\n"
    logfile.flush()

    if m["fqbn"].startswith("energia:"):
        os.chdir(energia_ide_path)
        builder = "./energia"
    else:
        os.chdir(arduino_ide_path)
        builder = "./arduino"

    fqbn = m["fqbn_adv"] if "fqbn_adv" in m.keys() else m["fqbn"]
    cmd = [
        builder,
        "--verbose",
        "--verify",
        "--board", fqbn,
        fn
    ]
    #print cmd
    rc = call(cmd, stdout=logfile, stderr=logfile)
    if rc:
        print "Failed"
        data['failed'].add(m["fqbn"])
    else:
        print "OK"
        data['built'].add(m["fqbn"])
        if m["fqbn"] in data['failed']:
            data['failed'].remove(m["fqbn"])


    with open(datafile, 'w') as fp:
        json.dump({
          '_stats': {
            'failed': len(data['failed']),
            'built': len(data['built']),
          },
          'failed': sorted(list(data['failed'])),
          'built': sorted(list(data['built'])),
          'broken': sorted(data['built'].intersection(data['failed'])),
        }, fp, sort_keys=True, indent=4)

print "=================="
if len(data['built']):
    print " OK:  ", len(data['built'])
if len(data['failed']):
    print " Fail:", len(data['failed'])
