#!/usr/bin/env python
import sys
import os
import argparse
from pcbnew import *


def layer_name_parser(s):
    parts = s.split('=')
    if len(parts) != 2:
        raise argparse.ArgumentTypeError("Invalid layer renaming: " + s)
    else:
        return parts


parser = argparse.ArgumentParser(description='KiCAD PCB to GERBER converter')

parser.add_argument('--pcb',
                    required=True,
                    dest='pcb',
                    action='store',
                    help='A foo.kicad_pcb file')

parser.add_argument('--output-directory',
                    required=True,
                    dest='output_directory',
                    action='store',
                    help='Directory to store output files')

parser.add_argument('--detect-files-only',
                    dest='detect_files_only',
                    action='store_true',
                    help='Don\'t create the GERBER files, just list the files to be created')

parser.add_argument('--create-drill-map-file',
                    dest='create_drill_map_file',
                    action='store_true',
                    help='Create drill map file')

parser.add_argument('--protel-extensions',
                    dest='protel_extensions',
                    action='store_true',
                    help='Use Protel filename extensions instead of .gbr')

parser.add_argument('--uppercase-extensions',
                    action='store_true',
                    help='Uppercase all extensions')

parser.add_argument('--layer-extension',
                    dest='layer_extensions',
                    metavar='LAYER_AND_EXTENSION',
                    action='append',
                    type=layer_name_parser,
                    help='Set the file extension of a KiCAD layer. Format: <KiCAD Layer>=<extension>, example: F.SilkS=GSILK')

args = parser.parse_args()
# print "args: " + str(args)
# print "args.name_layer: " + str(args.name_layers)

renames = {}
if args.layer_extensions is not None:
    for s in args.layer_extensions:
        renames[s[0]] = s[1]
# print("renames: " + str(renames))

board = LoadBoard(args.pcb)


class Plan:
    def __init__(self, layerNum, layerName, description):
        self.layerNum = layerNum
        self.layerName = layerName
        self.description = description
        self.postfix = ""
        self.ext = None

    @staticmethod
    def standard(layerNum, description):
        layerName = board.GetLayerName(layerNum)
        return Plan(layerNum, layerName, description)

    @staticmethod
    def copper(layerNum):
        layerName = board.GetLayerName(layerNum)
        description = "Copper Layer " + layerName
        return Plan(layerNum, layerName, description)


plot_plan = [Plan.standard(layerNum, description) for (layerNum, description) in [
    (F_SilkS, "Silk front"),
    (F_Mask, "Mask front"),
    (F_Paste, "Paste front"),
    (B_SilkS, "Silk bottom"),
    (B_Mask, "Mask bottom"),
    (B_Paste, "Paste bottom"),
    (Edge_Cuts, "Edges")]]

layers = board.GetEnabledLayers()
for layerNum in layers.CuStack():
    plot_plan.append(Plan.copper(layerNum))

pctl = PLOT_CONTROLLER(board)
popt = pctl.GetPlotOptions()
popt.SetOutputDirectory(args.output_directory)

# A nasty hack to get the base filename
pctl.SetLayer(F_Cu)
pctl.OpenPlotfile("", PLOT_FORMAT_GERBER, "")
filename = pctl.GetPlotFileName()
try:
    os.remove(filename)
except:
    pass
pctl.ClosePlot()

if args.protel_extensions:
    popt.SetUseGerberProtelExtensions(True)

basename = os.path.splitext(filename)[0]

drlFileOut = drlFile = basename + ".drl"
drlNpthFileOut = drlNpthFile = basename + "-NPTH.drl"

if args.protel_extensions:
    n, e = os.path.splitext(drlFileOut)
    drlFileOut = n + ".txt"

if args.uppercase_extensions:
    n, e = os.path.splitext(drlFileOut)
    drlFileOut = n + e.upper()
    n, e = os.path.splitext(drlNpthFileOut)
    drlNpthFileOut = n + e.upper()

values = vars(args)
for plan in plot_plan:
    pctl.SetLayer(plan.layerNum)
    pctl.OpenPlotfile("", PLOT_FORMAT_GERBER, plan.description)
    filename = pctl.GetPlotFileName()
    pctl.ClosePlot()
    # By opening and closing the plot we create an empty plot file.
    try:
        os.remove(filename)
    except:
        pass

    filename, ext = os.path.splitext(filename)
    if args.uppercase_extensions:
        ext = ext.upper()

    if plan.layerName in renames:
        ext = "." + renames[plan.layerName]

    # if plan.arg is not None:
    #     newExt = values[plan.arg]
    #     if newExt is not None:
    #         ext = "." + newExt

    # if not args.protel_extensions:
    plan.postfix = plan.layerName
    plan.filename = basename + "-" + plan.postfix + ext

    # print "filename = " + plan.filename + ", postfix=" + plan.postfix
    # print "filename: " + plan.filename

if args.detect_files_only:
    for plan in plot_plan:
        print
        plan.filename

    if args.protel_extensions:
        print
        drlFileOut
        print
        drlNpthFileOut
    sys.exit(0)

# Set some important plot options:
popt.SetPlotFrameRef(False)
popt.SetLineWidth(FromMM(0.35))

popt.SetAutoScale(False)
popt.SetScale(1)
popt.SetMirror(False)
popt.SetUseGerberAttributes(True)
popt.SetScale(1)
popt.SetUseAuxOrigin(True)

# This by gerbers only (also the name is truly horrid!)
popt.SetSubtractMaskFromSilk(False)

for plan in plot_plan:
    pctl.SetLayer(plan.layerNum)

    # print "filename = " + plan.filename + ", postfix=" + plan.postfix
    pctl.OpenPlotfile(plan.postfix, PLOT_FORMAT_GERBER, plan.description)

    actualFilename = pctl.GetPlotFileName()
    expectedFilename = plan.filename

    if expectedFilename != actualFilename:
        os.rename(actualFilename, expectedFilename)

    pctl.PlotLayer()
    pctl.ClosePlot()

popt.SetDrillMarksType(PCB_PLOT_PARAMS.FULL_DRILL_SHAPE)

drlwriter = EXCELLON_WRITER(board)
drlwriter.SetMapFileFormat(PLOT_FORMAT_GERBER)

mirror = False
minimalHeader = False
offset = wxPoint(0, 0)
# False to generate 2 separate drill files (one for plated holes, one for non plated holes)
# True to generate only one drill file
mergeNPTH = False
drlwriter.SetOptions(mirror, minimalHeader, offset, mergeNPTH)

metricFmt = True
drlwriter.SetFormat(metricFmt)

genDrl = True
genMap = args.create_drill_map_file

drlwriter.CreateDrillandMapFilesSet(pctl.GetPlotDirName(), genDrl, genMap)

if drlFile != drlFileOut:
    os.rename(drlFile, drlFileOut)
    pass

if drlFile != drlNpthFileOut:
    os.rename(drlNpthFile, drlNpthFileOut)
    pass