#!/usr/bin/env python

from __future__ import print_function
import serial
import os
import argparse
from clint.textui import prompt, validators, colored, puts

## Global Vars
VERSION = "1.0"
directory = os.getcwd()
ard_template = "\n\
#include <Arduino.h>\n\
#include <Wire.h>\n\
\n\
\n\
void setup() {\n\
}\n\
\n\
void loop() {\n\
}\n\
"

## Command Parser
parser = argparse.ArgumentParser(description='Arduino Makefile and boilerplate project generator. For use with Ard-Makefile: https://github.com/sudar/Arduino-Makefile. Script created by John Whittington https://github.com/tuna-f1sh 2017\n\nVersion: ' + VERSION, usage='"ardmk-init -b uno -quiet -project" Automonously create boiler plate Arduino Uno project in current working directory with same name. See --help for more.')
parser.add_argument('-v', '--verbose', action='store_true', help="print file contents during creation")
parser.add_argument('-d', '--directory', default=directory, help='directory to run generator')
parser.add_argument('-b', '--board', default='uno', help='board tag')
parser.add_argument('-u', '--micro', default='AUTO', help='microcontroller on board')
parser.add_argument('-f', '--freq', default='AUTO', help='mlock frequency')
parser.add_argument('-p', '--port', default='AUTO', help='monitor port')
parser.add_argument('-n', '--name', default=os.path.basename(directory), help='project name')
parser.add_argument('-q', '--quiet', action='store_true', help='run quiet without user prompts')
parser.add_argument('-P', '--project', action='store_true', help='create boilerplate project with src, lib and bin folder structure')
parser.add_argument('-t', '--template', action='store_true', help='create bare minimum Arduino source file')
args = parser.parse_args()

directory = args.directory

def generateMakefile():
    # Header
    fileContents = "# Generated by ard-make version " + VERSION + "\n\n"

    # Basic
    if not args.quiet:
        puts(colored.cyan("Generating Arduino Ard-Makefile project in " + os.path.abspath(directory)))
        btag = prompt.query('Board tag?', default='uno')
        if not btag == 'uno':
            bsub = prompt.query('Board sub micro?', default='atmega328')
            f_cpu = prompt.query('Board frequency', default='16000000L')
        else:
            bsub = 'AUTO'
            f_cpu = 'AUTO'
        monitor_port = prompt.query('Arduino port?', default='AUTO')
    else:
        btag = args.board
        bsub = args.micro
        f_cpu = args.freq
        monitor_port = args.port

    fileContents += checkDefine('BOARD_TAG', btag)
    fileContents += checkDefine('BOARD_SUB', bsub)
    fileContents += checkDefine('F_CPU', f_cpu)
    fileContents += checkDefine('MONITOR_PORT', monitor_port)

    # Extended
    if not args.quiet:
        if not prompt.yn('Extended options?', default='n'):
            if not prompt.yn('Define local folders?', default='n'):
                src_dir = prompt.query('Sources folder (Makefile will be created here)?', default='', validators=[])
                userlibs = prompt.query('Library folder (will create if does not exist) - AUTO is Sketchbook directory?', default='AUTO', validators=[])
                obj_dir = prompt.query('Output directory?', default='AUTO', validators=[])
            else:
                src_dir = ''
                userlibs = 'AUTO'
                obj_dir = 'AUTO'
            boards_txt = prompt.query('Boards file?', default='AUTO')
            isp_prog = prompt.query('ISP programmer?', default='atmelice_isp')
            isp_port = prompt.query('ISP port?', default='AUTO')
            if not prompt.yn('Quiet make?', default='n'):
                fileContents += "ARDUINO_QUIET = 1\n"

            fileContents += checkDefine('ISP_PROG', isp_prog)
            fileContents += checkDefine('ISP_PORT', isp_port)
            fileContents += checkDefine('BOARDS_TXT', boards_txt)

            # Check andd create folders
            checkCreateFolder(src_dir)
            checkCreateFolder(userlibs)
            checkCreateFolder(obj_dir)

            # Makefile will be in src_dir so lib and bin must be relative
            if src_dir:
                userlibs = "../" + userlibs
                obj_dir = "../" + obj_dir

            fileContents += checkDefine('USER_LIB_PATH', userlibs)
            fileContents += checkDefine('OBJDIR', obj_dir)
        else:
            src_dir = ''

        if args.template or not prompt.yn('Create template Arduino source?', default='n'):
            sourceFilename = prompt.query('Name of project?', default=os.path.basename(os.getcwd()))
            if src_dir:
                writeTemplate(src_dir + "/" + sourceFilename)
            else:
                writeTemplate(sourceFilename)
            fileContents += checkDefine('TARGET', sourceFilename)

    else:
        if args.project:
            src_dir = 'src'
            userlibs = 'lib'
            obj_dir = 'bin'
        else:
            src_dir = ''
            userlibs = 'AUTO'
            obj_dir = 'AUTO'

        # Check andd create folders
        checkCreateFolder(src_dir)
        checkCreateFolder(userlibs)
        checkCreateFolder(obj_dir)

        # Makefile will be in src_dir so lib and bin must be relative
        if src_dir:
            userlibs = "../" + userlibs
            obj_dir = "../" + obj_dir

        fileContents += checkDefine('USER_LIB_PATH', userlibs)
        fileContents += checkDefine('OBJDIR', obj_dir)

        if args.project or args.template:
            if src_dir:
                writeTemplate(src_dir + "/" + args.name)
            else:
                writeTemplate(args.name)
            fileContents += checkDefine('TARGET', args.name)

    if not "ARDMK_DIR" in os.environ:
        if args.quiet:
            puts(colored.magenta('Warning: ARDMK_DIR environment variable not defined. Must be defined for Makefile to work'))
        else:
            ardmk = prompt.query('Arduino Makefile path?', default='/usr/share/arduino', validators=[validators.PathValidator()])
            ardmk = "ARDMK_DIR := " + ardmk + "\n"

    fileContents += "\ninclude $(ARDMK_DIR)/Arduino.mk"

    # Add forward slash if source directory exists
    if src_dir:
        writeToMakefile(fileContents, (src_dir + "/"))
    else:
        writeToMakefile(fileContents, "")

    return fileContents

def writeToMakefile(fileContents, path):
    makefile = open(path + "Makefile", 'w')
    puts(colored.cyan("Writing Makefile..."))
    if args.verbose:
        puts(colored.yellow(fileContents))
    makefile.write(fileContents)
    makefile.close()

def writeTemplate(filename):
    puts(colored.cyan("Writing " + os.path.abspath(filename) + ".ino..."))
    if os.path.isfile(filename + '.ino'):
        if args.quiet:
            puts(colored.red(filename + '.ino' + ' already exists! Stopping.'))
            return
        puts(colored.red(filename + '.ino' + ' already exists! Overwrite?'))
        if prompt.yn('Continue?', default='n'):
            return
    src = open((filename + ".ino"),'w')
    if args.verbose:
        puts(colored.yellow(ard_template))
    src.write("/* Project: " + filename + " */\n" + ard_template)
    src.close()

def checkCreateFolder(folder):
    if folder and not folder == 'AUTO':
        if not os.path.exists(folder):
            puts(colored.cyan(("Creating " + os.path.abspath(folder) + " folder")))
            os.makedirs(folder)

def checkDefine(define, user):
    if user and not user == 'AUTO':
        return define + " = " + user + "\n"
    else:
        return ""

def main():
    # Create directory if not exist
    checkCreateFolder(directory)
    # Change to dir so all commands are run relative
    os.chdir(directory)
    if os.path.isfile('Makefile'):
        if args.quiet:
            puts(colored.red('Makefile in ' + os.path.abspath(directory) + ' already exists! Stopping.'))
            return
        puts(colored.red('Makefile in ' + os.path.abspath(directory) + ' already exists! Overwrite?'))
        if prompt.yn('Continue?', default='n'):
            return
    generateMakefile();

main()