#!/usr/bin/env python3
"""
Generate a skeleton for a new ChuGin.
"""

import sys, re, os, io, tarfile, base64

if len(sys.argv) != 2 and len(sys.argv) != 3:
    print("usage: chuginate chugin_name [destination_directory]")
    sys.exit(-1)

chugin_name = sys.argv[1]
if len(sys.argv) >= 3:
    dest_dir = sys.argv[2]
else:
    dest_dir = sys.argv[1]
    os.mkdir(dest_dir)

chugin_lcname = chugin_name.lower()
chugin_ucname = chugin_name.upper()
chugin_initials = re.sub('[a-z]', '', chugin_name).lower()
if len(chugin_initials) == 0: chugin_initials = chugin_name[0]
chugin_header_path = 'chuck/include'

USE_EXISTING_CHUCK_HEADERS = False
# if the chuck headers already exist
if os.path.isdir("%s/../chuck/include" % (dest_dir)):
    chugin_header_path = "../chuck/include/"
    USE_EXISTING_CHUCK_HEADERS = True

def substitute(text):
    global chugin_name, chugin_lcname, chugin_ucname, chugin_initials, chugin_header_path
    text = re.sub(r'\%\(CHUGIN_NAME\)\%', chugin_name, text)
    text = re.sub(r'\%\(CHUGIN_LCNAME\)\%', chugin_lcname, text)
    text = re.sub(r'\%\(CHUGIN_UCNAME\)\%', chugin_ucname, text)
    text = re.sub(r'\%\(CHUGIN_INITIALS\)\%', chugin_initials, text)
    text = re.sub(r'\%\(CHUGIN_HEADER_PATH\)\%', chugin_header_path, text)
    return text

# print "name: %s lc: %s initials: %s" % (chugin_name, chugin_lcname, chugin_initials)

code = dict()
tgz = dict()
filepath = dict()
newlines = dict()

code['cpp'] = u'''//-----------------------------------------------------------------------------
// Entaro ChucK Developer!
// This is a chugin boilerplate, generated by chuginate!
//-----------------------------------------------------------------------------
// NOTE by default, chuginate generates a new UGen subclass in this file
//      but it is possible, of course, to create non-UGen classes in a chugin!
// To modify this generated file for a non-UGen class...
//      1. in QUERY->begin_class(), change "UGen" to a different ChucK class
//         (e.g., `QUERY->begin_class(QUERY, "%(CHUGIN_NAME)%", "Object");`)
//      2. remove or commment out the line containing QUERY->add_ugen_func()
//      3. that's it; the rest is no different for UGens/non-UGens
//-----------------------------------------------------------------------------
// NOTE once you have built this into a chugin (%(CHUGIN_NAME)%.chug), here are a few
//      helpful tools for testing / probing / verifying your new chugin!
//
// chuginate also generated a %(CHUGIN_NAME)%-test.ck boilerplate ChucK program
//      to help test your chugin (see %(CHUGIN_NAME)%-test.ck for more instructions)
//
// run `chuck --chugin-probe` to probe what chugins would be loaded, and
//      from where in the chugin search paths
//
// run `chuck -v3 --loop` to see what chugins are actually loaded at runtime,
//      with more info and error reporting than with --chugin-probe
//
// other helpful chugin-related flags include:
//      --chugin:<filename>
//      --chugin-path:(path) / -G(path)
//      --chugin-load:{on/off}
//
// for more information on command-line options:
//      https://chuck.stanford.edu/doc/program/options.html
// for more information on chugins:
//      https://chuck.stanford.edu/extend/
//-----------------------------------------------------------------------------
// happy chucking & chugging!
//-----------------------------------------------------------------------------

// include chugin header
#include "chugin.h"

// general includes
#include <iostream>


// declaration of chugin constructor
CK_DLL_CTOR( %(CHUGIN_LCNAME)%_ctor );
// declaration of chugin desctructor
CK_DLL_DTOR( %(CHUGIN_LCNAME)%_dtor );

// example of getter/setter
CK_DLL_MFUN( %(CHUGIN_LCNAME)%_setParam );
CK_DLL_MFUN( %(CHUGIN_LCNAME)%_getParam );

// for chugins extending UGen, this is mono synthesis function for 1 sample
CK_DLL_TICK( %(CHUGIN_LCNAME)%_tick );

// this is a special offset reserved for chugin internal data
t_CKINT %(CHUGIN_LCNAME)%_data_offset = 0;


//-----------------------------------------------------------------------------
// class definition for internal chugin data
// (NOTE this isn't strictly necessary, but is one example of a recommended approach)
//-----------------------------------------------------------------------------
class %(CHUGIN_NAME)%
{
public:
    // constructor
    %(CHUGIN_NAME)%( t_CKFLOAT fs )
    {
        m_param = 0;
    }

    // for chugins extending UGen
    SAMPLE tick( SAMPLE in )
    {
        // default: this passes whatever input is patched into chugin
        return in;
    }

    // set parameter example
    t_CKFLOAT setParam( t_CKFLOAT p )
    {
        m_param = p;
        return p;
    }

    // get parameter example
    t_CKFLOAT getParam() { return m_param; }
    
private:
    // instance data
    t_CKFLOAT m_param;
};


//-----------------------------------------------------------------------------
// info function: ChucK calls this when loading/probing the chugin
// NOTE: please customize these info fields below; they will be used for
// chugins loading, probing, and package management and documentation
//-----------------------------------------------------------------------------
CK_DLL_INFO( %(CHUGIN_NAME)% )
{
    // the version string of this chugin, e.g., "v1.2.1"
    QUERY->setinfo( QUERY, CHUGIN_INFO_CHUGIN_VERSION, "" );
    // the author(s) of this chugin, e.g., "Alice Baker & Carl Donut"
    QUERY->setinfo( QUERY, CHUGIN_INFO_AUTHORS, "" );
    // text description of this chugin; what is it? what does it do? who is it for?
    QUERY->setinfo( QUERY, CHUGIN_INFO_DESCRIPTION, "" );
    // (optional) URL of the homepage for this chugin
    QUERY->setinfo( QUERY, CHUGIN_INFO_URL, "" );
    // (optional) contact email
    QUERY->setinfo( QUERY, CHUGIN_INFO_EMAIL, "" );
}


//-----------------------------------------------------------------------------
// query function: ChucK calls this when loading the chugin
// modify this function to define this chugin's API and language extensions
//-----------------------------------------------------------------------------
CK_DLL_QUERY( %(CHUGIN_NAME)% )
{
    // generally, don't change this...
    QUERY->setname( QUERY, "%(CHUGIN_NAME)%" );

    // ------------------------------------------------------------------------
    // begin class definition(s); will be compiled, verified,
    // and added to the chuck host type system for use
    // ------------------------------------------------------------------------
    // NOTE to create a non-UGen class, change the second argument
    // to extend a different ChucK class (e.g., "Object")
    QUERY->begin_class( QUERY, "%(CHUGIN_NAME)%", "UGen" );

    // register default constructor
    QUERY->add_ctor( QUERY, %(CHUGIN_LCNAME)%_ctor );
    // NOTE constructors can be overloaded like any other functions,
    // each overloaded constructor begins with `QUERY->add_ctor()`
    // followed by a sequence of `QUERY->add_arg()`

    // register the destructor (probably no need to change)
    QUERY->add_dtor( QUERY, %(CHUGIN_LCNAME)%_dtor );

    // for UGens only: add tick function
    // NOTE a non-UGen class should remove or comment out this next line
    QUERY->add_ugen_func( QUERY, %(CHUGIN_LCNAME)%_tick, NULL, 1, 1 );
    // NOTE: if this is to be a UGen with more than 1 channel,
    // e.g., a multichannel UGen -- will need to use add_ugen_funcf()
    // and declare a tickf function using CK_DLL_TICKF

    // example of adding setter method
    QUERY->add_mfun( QUERY, %(CHUGIN_LCNAME)%_setParam, "float", "param" );
    // example of adding argument to the above method
    QUERY->add_arg( QUERY, "float", "arg" );

    // example of adding getter method
    QUERY->add_mfun( QUERY, %(CHUGIN_LCNAME)%_getParam, "float", "param" );
    
    // this reserves a variable in the ChucK internal class to store 
    // referene to the c++ class we defined above
    %(CHUGIN_LCNAME)%_data_offset = QUERY->add_mvar( QUERY, "int", "@%(CHUGIN_INITIALS)%_data", false );

    // ------------------------------------------------------------------------
    // end the class definition
    // IMPORTANT: this MUST be called to each class definition!
    // ------------------------------------------------------------------------
    QUERY->end_class( QUERY );

    // wasn't that a breeze?
    return TRUE;
}


// implementation for the default constructor
CK_DLL_CTOR( %(CHUGIN_LCNAME)%_ctor )
{
    // get the offset where we'll store our internal c++ class pointer
    OBJ_MEMBER_INT( SELF, %(CHUGIN_LCNAME)%_data_offset ) = 0;
    
    // instantiate our internal c++ class representation
    %(CHUGIN_NAME)% * %(CHUGIN_INITIALS)%_obj = new %(CHUGIN_NAME)%( API->vm->srate(VM) );
    
    // store the pointer in the ChucK object member
    OBJ_MEMBER_INT( SELF, %(CHUGIN_LCNAME)%_data_offset ) = (t_CKINT)%(CHUGIN_INITIALS)%_obj;
}


// implementation for the destructor
CK_DLL_DTOR( %(CHUGIN_LCNAME)%_dtor )
{
    // get our c++ class pointer
    %(CHUGIN_NAME)% * %(CHUGIN_INITIALS)%_obj = (%(CHUGIN_NAME)% *)OBJ_MEMBER_INT( SELF, %(CHUGIN_LCNAME)%_data_offset );
    // clean up (this macro tests for NULL, deletes, and zeros out the variable)
    CK_SAFE_DELETE( %(CHUGIN_INITIALS)%_obj );
    // set the data field to 0
    OBJ_MEMBER_INT( SELF, %(CHUGIN_LCNAME)%_data_offset ) = 0;
}


// implementation for tick function (relevant only for UGens)
CK_DLL_TICK( %(CHUGIN_LCNAME)%_tick )
{
    // get our c++ class pointer
    %(CHUGIN_NAME)% * %(CHUGIN_INITIALS)%_obj = (%(CHUGIN_NAME)% *)OBJ_MEMBER_INT(SELF, %(CHUGIN_LCNAME)%_data_offset);
 
    // invoke our tick function; store in the magical out variable
    if( %(CHUGIN_INITIALS)%_obj ) *out = %(CHUGIN_INITIALS)%_obj->tick( in );

    // yes
    return TRUE;
}


// example implementation for setter
CK_DLL_MFUN( %(CHUGIN_LCNAME)%_setParam )
{
    // get our c++ class pointer
    %(CHUGIN_NAME)% * %(CHUGIN_INITIALS)%_obj = (%(CHUGIN_NAME)% *)OBJ_MEMBER_INT( SELF, %(CHUGIN_LCNAME)%_data_offset );

    // get next argument
    // NOTE argument type must match what is specified above in CK_DLL_QUERY
    // NOTE this advances the ARGS pointer, so save in variable for re-use
    t_CKFLOAT arg1 = GET_NEXT_FLOAT( ARGS );
    
    // call setParam() and set the return value
    RETURN->v_float = %(CHUGIN_INITIALS)%_obj->setParam( arg1 );
}


// example implementation for getter
CK_DLL_MFUN(%(CHUGIN_LCNAME)%_getParam)
{
    // get our c++ class pointer
    %(CHUGIN_NAME)% * %(CHUGIN_INITIALS)%_obj = (%(CHUGIN_NAME)% *)OBJ_MEMBER_INT( SELF, %(CHUGIN_LCNAME)%_data_offset );

    // call getParam() and set the return value
    RETURN->v_float = %(CHUGIN_INITIALS)%_obj->getParam();
}
'''
code['test'] = u'''//--------------------------------------------------------------------
// This is a boilerplate ChucK program generated by chuginate,
//     to help you test your new chugin, ChuGin Developer!
//--------------------------------------------------------------------
// 1) try running this program after building your chugin
//    (the bulid process should yield a %(CHUGIN_NAME)%.chug file)
//
// 2) you can manullay load the chugin when you run this program
//    `chuck --chugin:%(CHUGIN_NAME)%.chug %(CHUGIN_NAME)%-test.ck`
//
// 3) OR you can put the chugin into your chugins search path
//    NOTE: not recommended until you feel the chugin to be
//    reasonably stable, as chugins in your chugins search paths
//    will automatically load every time you run `chuck` or
//    start the VM in miniAudicle...
//
// Want to see more information? Add the --verbose:3 (-v3) flag:
//    `chuck --chugin:%(CHUGIN_NAME)%.chug %(CHUGIN_NAME)%-test.ck -v3`
//--------------------------------------------------------------------

// instantiate a %(CHUGIN_NAME)%
%(CHUGIN_NAME)% obj;

// call obj.param() with argument of 5; same as obj.param(5)
5 => obj.param;

// print
<<< obj.param() >>>;
'''
code['makefile'] = u'''
# chugin name
CHUGIN_NAME=%(CHUGIN_NAME)%

# all of the c/cpp files that compose this chugin
C_MODULES=
CXX_MODULES=%(CHUGIN_NAME)%.cpp

# where to find chugin.h
CK_SRC_PATH?=%(CHUGIN_HEADER_PATH)%

# where to install chugin
CHUGIN_PATH?=/usr/local/lib/chuck


# ---------------------------------------------------------------------------- #
# you won't generally need to change anything below this line for a new chugin #
# ---------------------------------------------------------------------------- #

# default target: print usage message and quit
current: 
	@echo "[chugin build]: please use one of the following configurations:"
	@echo "   make linux, make mac, make web, or make win32"

ifneq ($(CK_TARGET),)
.DEFAULT_GOAL:=$(CK_TARGET)
ifeq ($(MAKECMDGOALS),)
MAKECMDGOALS:=$(.DEFAULT_GOAL)
endif
endif

.PHONY: mac osx linux linux-pulse linux-oss linux-jack linux-alsa win32
mac osx linux linux-pulse linux-oss linux-jack linux-alsa: all

win32:
	make -f makefile.win

CC=gcc
CXX=gcc
LD=g++

ifneq (,$(strip $(filter mac osx,$(MAKECMDGOALS))))
include makefile.mac
endif

ifneq (,$(strip $(filter linux,$(MAKECMDGOALS))))
include makefile.linux
endif

ifneq (,$(strip $(filter linux-oss,$(MAKECMDGOALS))))
include makefile.linux
endif

ifneq (,$(strip $(filter linux-pulse,$(MAKECMDGOALS))))
include makefile.linux
endif

ifneq (,$(strip $(filter linux-jack,$(MAKECMDGOALS))))
include makefile.linux
endif

ifneq (,$(strip $(filter linux-alsa,$(MAKECMDGOALS))))
include makefile.linux
endif

ifneq ($(CHUCK_DEBUG),)
FLAGS+= -g
else
FLAGS+= -O3
endif

ifneq ($(CHUCK_STRICT),)
FLAGS+= -Werror
endif

# default: build a dynamic chugin
CK_CHUGIN_STATIC?=0

ifeq ($(CK_CHUGIN_STATIC),0)
SUFFIX=.chug
else
SUFFIX=.schug
FLAGS+= -D__CK_DLL_STATIC__
endif
# webchugin extension
WEBSUFFIX=.wasm

C_OBJECTS=$(addsuffix .o,$(basename $(C_MODULES)))
CXX_OBJECTS=$(addsuffix .o,$(basename $(CXX_MODULES)))

CHUG=$(addsuffix $(SUFFIX),$(CHUGIN_NAME))
WEBCHUG=$(addsuffix $(WEBSUFFIX),$(CHUG))

all: $(CHUG)

$(CHUG): $(C_OBJECTS) $(CXX_OBJECTS)
ifeq ($(CK_CHUGIN_STATIC),0)
	$(LD) $(LDFLAGS) -o $@ $^
else
	ar rv $@ $^
	ranlib $@
endif

$(C_OBJECTS): %.o: %.c
	$(CC) $(FLAGS) -c -o $@ $<

$(CXX_OBJECTS): %.o: %.cpp $(CK_SRC_PATH)/chugin.h
	$(CXX) $(FLAGS) -c -o $@ $<

# build as webchugin
web:
	emcc -O3 -s SIDE_MODULE=1 -s DISABLE_EXCEPTION_CATCHING=0 -fPIC -Wformat=0 \
	-I $(CK_SRC_PATH) $(CXX_MODULES) $(C_MODULES) -o $(WEBCHUG)

install: $(CHUG)
	mkdir -p $(CHUGIN_PATH)
	cp $^ $(CHUGIN_PATH)
	chmod 755 $(CHUGIN_PATH)/$(CHUG)

clean: 
	rm -rf $(C_OBJECTS) $(CXX_OBJECTS) $(CHUG) $(WEBCHUG) Release Debug
'''
code['makefile.mac'] = u'''#-----------------------------------
# makefile.mac
# macOS-specific build configuration
#-----------------------------------

# to build for the native architecture: (leave blank)
# ARCHS?=
#
# to build for intel:
# ARCHS?=x86_64
#
# to build for apple silicon:
# ARCHS?=arm64
#
# to build a universal=binary chugin:
# ARCHS?=x86_64 arm64
ARCHS?=

# construct compiler option string
ARCHOPTS=$(addprefix -arch ,$(ARCHS))

# compiler flags
FLAGS+=-mmacosx-version-min=10.9 -I$(CK_SRC_PATH) $(ARCHOPTS) -fPIC
# linker flags
LDFLAGS+=-mmacosx-version-min=10.9 -shared -lc++ $(ARCHOPTS)

# which C++ compiler
CXX=clang++
# which linker to user
LD=clang++
'''
code['makefile.linux'] = u'''#-----------------------------------
# makefile.linux
# Linux-specific build configuration
#-----------------------------------

# uncomment to override where `make install` puts chugin (see also: makefile)
# CHUGIN_PATH=/usr/local/lib/chuck

# compiler flags
FLAGS=-D__LINUX_ALSA__ -D__PLATFORM_LINUX__ -I$(CK_SRC_PATH) -fPIC
# linker flags
LDFLAGS=-shared -lstdc++

# which C++ compiler to use
CXX=g++
# which linker to use
LD=gcc
'''
code['makefile.win'] = u'''#--------------------------------------
# makefile.win32
# Windows-specific build configurations
# (supports 32-bit and 64-bit)
#--------------------------------------

# command line build tool
MSBUILD=msbuild.exe

# configuration
ifneq (,$(CHUCK_DEBUG))
CONFIG=Debug
CHUG_BIN=Debug/%(CHUGIN_NAME)%.chug
else
CONFIG=Release
CHUG_BIN=Release/%(CHUGIN_NAME)%.chug
endif

# targets
default: $(CHUG_BIN)

$(CHUG_BIN): 
	$(MSBUILD) /p:Configuration=$(CONFIG) 

clean:
	$(MSBUILD) /p:Configuration=$(CONFIG) /t:Clean

'''
code['.vcxproj'] = u'''<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)/Microsoft.Cpp.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
    <TargetExt>.chug</TargetExt>
    <IncludePath>chuck/include;$(IncludePath)</IncludePath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
    <TargetExt>.chug</TargetExt>
    <IncludePath>chuck/include;$(IncludePath)</IncludePath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
    <TargetExt>.chug</TargetExt>
    <IncludePath>chuck/include;$(IncludePath)</IncludePath>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
    <TargetExt>.chug</TargetExt>
    <IncludePath>chuck/include;$(IncludePath)</IncludePath>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(CHUGIN_UCNAME)%_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(CHUGIN_UCNAME)%_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(CHUGIN_UCNAME)%_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(CHUGIN_UCNAME)%_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="%(CHUGIN_NAME)%.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="%(CHUGIN_NAME)%.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Targets" />
</Project>
'''

if not USE_EXISTING_CHUCK_HEADERS:
    tgz['chuck'] = u'''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'''

filepath['cpp'] = "%s/%s.cpp" % (dest_dir, chugin_name)
filepath['test'] = "%s/%s-test.ck" % (dest_dir, chugin_name)
filepath['makefile'] = "%s/makefile" % (dest_dir)
filepath['makefile.mac'] = "%s/makefile.mac" % (dest_dir)
filepath['makefile.linux'] = "%s/makefile.linux" % (dest_dir)
filepath['makefile.win'] = "%s/makefile.win" % (dest_dir)
filepath['.vcxproj'] = "%s/%s.vcxproj" % (dest_dir, chugin_name)
filepath['chuck'] = "%s/chuck.tgz" % (dest_dir)

newlines['.vcxproj'] = '\r\n'

code['cpp'] = substitute(code['cpp'])
code['test'] = substitute(code['test'])
code['makefile'] = substitute(code['makefile'])
code['makefile.win'] = substitute(code['makefile.win'])
code['.vcxproj'] = substitute(code['.vcxproj'])


for key in code:
    if key in newlines:
        nl = newlines[key]
    else:
        nl = '\n'
    with io.open(filepath[key], "wt", newline=nl) as f:
        f.write(code[key])

for key in tgz:
    with io.open(filepath[key], "wb") as f:
        f.write(base64.b64decode(tgz[key]))
    with tarfile.open(filepath[key]) as tar:
        tar.extractall(os.path.dirname(filepath[key]))
    os.unlink(filepath[key])


