############# Names and dirs #############

PROGNAME = CMSDKTest$(EXT)
LIBNAME = libCMSDK$(EXT).a
PY2NAME = _cmsdk2$(EXTLOW).so
PY3NAME = _cmsdk3$(EXTLOW).so

BINDIR = bin
LIBDIR = lib
SRCDIR = src
BUILDDIR = build$(EXTLOW)

INCLUDEDIRS = include
LIBRARIES = 

######## Include version info ########

include Makefile.ver
CMSDK_REVISION := $(shell date +%y%m%d)
VERSION = $(CMSDK_VERMAJOR).$(CMSDK_VERMINOR).$(CMSDK_REVISION)$(CMSDK_VERSUBTEXT)
BSDDISTDIR = CMSDK_BSD_$(VERSION)
DATE_TODAY = `date +%d\ %B\ %Y`
YEAR_TODAY = `date +%Y`

######## Licensing ########

BSD_HEADER_TEMPLATE = licences/bsd.header.template.txt
BSD_LICENCE_TEMPLATE = licences/bsd.licence.template.txt
BSD_HEADER = licences/bsd.header.txt
BSD_LICENCE = licences/licence-bsd.txt

DO_NOT_LICENCE_FILES = -not -name xml_parser.\* -not -name bimap.h -not -name direntwin.h

############# Include system stuff #############

include Makefile.sys

############# Files to compile #############


CPPFILES =  ComponentMemory.cpp ConsoleOutput.cpp
CPPFILES += DataMapsMemory.cpp DataMessage.cpp MemoryController.cpp TemporalMemory.cpp HTML.cpp
CPPFILES += MemoryRequestConnection.cpp MemoryRequestServer.cpp MemoryRequestQueues.cpp
CPPFILES += MemoryCommander.cpp MemoryManager.cpp NetworkConnections.cpp
CPPFILES += NetworkManager.cpp NetworkProtocols.cpp ProcessMemory.cpp PsyAPI.cpp
CPPFILES += PsyInternal.cpp PsySpace.cpp PsySSL.cpp PsyTime.cpp Subscriptions.cpp
CPPFILES += ThreadManager.cpp MovingAverage.cpp UnitTest_CMSDK.cpp UnitTestFramework.cpp Utils.cpp Stats.cpp
CPPFILES += xml_parser.cpp MessageIndex.cpp jsmn.cpp Bitmap.cpp Base64.cpp Observations.cpp VantagePoints.cpp
CPPFILES += RequestGateway.cpp RequestClient.cpp RequestExecutor.cpp RESTAPI.cpp MathClasses.cpp MessagePlayer.cpp
CPPFILES += hash/keccak.cpp hash/sha3.cpp hash/crc32.cpp hash/md5.cpp hash/sha1.cpp hash/sha256.cpp hash/HashTest.cpp

PY2CPPFILES = cmsdk2$(EXTLOW)_wrap.cxx
PY3CPPFILES = cmsdk3$(EXTLOW)_wrap.cxx

PROG_CPPFILES = CMSDKTest.cpp

############# Setup dirs #############

PROGRAM = $(BINDESTDIR)/$(PROGNAME)
LIBRARY = $(LIBDESTDIR)/$(LIBNAME)
PY2LIB = $(BINDESTDIR)/$(PY2NAME)
PY3LIB = $(BINDESTDIR)/$(PY3NAME)

SRCFILES = $(patsubst %.cpp,$(SRCDIR)/%.cpp,$(CPPFILES))
OBJFILES = $(patsubst %.cpp,$(BUILDDIR)/%.o,$(CPPFILES))

PY2OBJFILES = $(patsubst %.cxx,$(BUILDDIR)/%.op2,$(PY2CPPFILES))
PY3OBJFILES = $(patsubst %.cxx,$(BUILDDIR)/%.op3,$(PY3CPPFILES))

PROG_SRCFILES = $(patsubst %.cpp,$(SRCDIR)/%.cpp,$(PROG_CPPFILES))
PROG_OBJFILES = $(patsubst %.cpp,$(BUILDDIR)/%.o,$(PROG_CPPFILES))

INCLUDES = $(patsubst %,-I% ,$(INCLUDEDIRS)) $(OPENSSL_CFLAGS)
LIBS = $(subst /arch/,/$(ARCH)/,$(LIBRARIES))

RESULT := $(shell if [ ! -d $(BINDIR) ]; then mkdir $(BINDIR); fi)
RESULT := $(shell if [ ! -d $(BINDESTDIR) ]; then mkdir $(BINDESTDIR); fi)
RESULT := $(shell if [ ! -d $(LIBDIR) ]; then mkdir $(LIBDIR); fi)
RESULT := $(shell if [ ! -d $(LIBDESTDIR) ]; then mkdir $(LIBDESTDIR); fi)
RESULT := $(shell if [ ! -d $(BUILDDIR) ]; then mkdir $(BUILDDIR); fi)
RESULT := $(shell if [ ! -d $(BUILDDIR)/hash ]; then mkdir $(BUILDDIR)/hash; fi)

############# Overall commands #############

all : $(LIBRARY) $(PROGRAM)
	@echo $(LIBRARY) and $(PROGRAM) ready

debug: all

profile: all

ssl: all

ssldebug: all

python2: $(LIBRARY) $(PY2LIB)

python3: $(LIBRARY) $(PY3LIB)

# Regenerate the Python 3 SWIG wrappers (release + debug) from cmsdk.i.
# Run this whenever cmsdk.i or the exposed headers change, then rebuild with
# `make python3`. SWIGWORDSIZE64 is passed on 64-bit builds so SWIG's int64/
# uint64 typedefs match the LP64 C++ ABI (long, not long long); without it the
# wrapper mis-declares std::vector<int64>/std::map<int64,...> and won't compile.
# SWIG, SWIGWORDFLAG and SWIG_AVAILABLE are defined in Makefile.sys (shared by
# CMSDK and System, both of which build the wrapper). See the note there for why
# -DSWIGWORDSIZE64 is Linux-only.
swig3:
	@echo Regenerating Python 3 SWIG wrappers from cmsdk.i ...
	$(SWIG) -c++ -python $(SWIGWORDFLAG) -module cmsdk3 -Iinclude -o src/cmsdk3_wrap.cxx cmsdk.i
	$(SWIG) -c++ -python $(SWIGWORDFLAG) -module cmsdk3debug -Iinclude -o src/cmsdk3debug_wrap.cxx cmsdk.i
	@echo Done. Now run 'make python3' to build the extension module.

ifneq ($(SWIG_AVAILABLE),)
# The checked-in src/cmsdk3*_wrap.cxx are LP64/Linux-flavoured. To build the
# Python bindings correctly on every platform WITHOUT dirtying those tracked
# files, regenerate an OS-correct wrapper into the build dir when swig is
# present and compile that. This explicit target overrides the generic
# $(BUILDDIR)/%.op3: $(SRCDIR)/%.cxx rule for the wrapper object, so the tracked
# src/ wrapper is left untouched. When swig is absent the build falls back to
# the committed src/ wrapper (unchanged Linux/Windows behaviour).
$(BUILDDIR)/cmsdk3$(EXTLOW)_wrap.cxx: cmsdk.i
	@mkdir -p $(@D)
	@echo Generating OS-correct SWIG wrapper $(@F) ...
	@$(SWIG) -c++ -python $(SWIGWORDFLAG) -module cmsdk3$(EXTLOW) -Iinclude -outdir $(BUILDDIR) -o $@ cmsdk.i

$(BUILDDIR)/cmsdk3$(EXTLOW)_wrap.op3: $(BUILDDIR)/cmsdk3$(EXTLOW)_wrap.cxx
	@mkdir -p $(@D)
	@echo Compiling generated $(<F)
	@$(CC) $(DEBUG) $(INCLUDES) $(PYTHON3INCLUDE) $(STANDARD) $(NOTLINK) $(OUTPUT_OPTION) $<
endif

############# Dependencies #############

$(BUILDDIR)/%.d: $(SRCDIR)/%.cpp
	@echo Making dependencies for $(<F)...
	@$(SHELL) -ec '$(CC) -MM $(INCLUDES) -D $(SYSTEM) $(STANDARD) $< \
		| sed '\''s/\($(*F)\)\.o[ :]*/\1.o $(@F) : /g'\'' > $@; \
		[ -s $@ ] || rm -f $@'

ifneq ($(MAKECMDGOALS),clean)
ifneq ($(MAKECMDGOALS),cleandebug)
ifneq ($(MAKECMDGOALS),totalclean)
ifneq ($(MAKECMDGOALS),info)
ifneq ($(MAKECMDGOALS),bsd)
  -include $(OBJFILES:.o=.d)
endif
endif
endif
endif
endif

############# Compiling #############

$(BUILDDIR)/%.o: $(SRCDIR)/%.cpp
	@mkdir -p $(@D)
	@echo Compiling $(<F)
	@$(CC) $(DEBUG) $(INCLUDES) $(STANDARD) $(NOTLINK) $(OUTPUT_OPTION) $<

$(BUILDDIR)/%.op2: $(SRCDIR)/%.cxx
	@mkdir -p $(@D)
	@echo Compiling $(<F)
	@$(CC) $(DEBUG) $(INCLUDES) $(PYTHON2INCLUDE) $(STANDARD) $(NOTLINK) $(OUTPUT_OPTION) $<

$(BUILDDIR)/%.op3: $(SRCDIR)/%.cxx
	@mkdir -p $(@D)
	@echo Compiling $(<F)
	@$(CC) $(DEBUG) $(INCLUDES) $(PYTHON3INCLUDE) $(STANDARD) $(NOTLINK) $(OUTPUT_OPTION) $<

############# Linking #############

$(PROGRAM): $(LIBRARY) $(PROG_OBJFILES)
	@echo Linking $(PROGNAME) $(SYSTEM)...
	@$(CC) $(DEBUG) $(STANDARD) $(PROG_OBJFILES) $(LIBRARY) $(LIBPATHS) $(OPENSSL_LDFLAGS) -o $(PROGRAM) $(LIBS) $(OTHERLIBS)

$(LIBRARY): $(OBJFILES)
	@echo Creating $(LIBRARY)...
	@$(RM) -f $(LIBRARY)
	@$(AR) $(ARFLAGS) $(LIBRARY) $(OBJFILES)
	@$(RANLIB) $(LIBRARY)

$(PY2LIB): $(LIBRARY) $(PY2OBJFILES)
	@echo Linking $(PY2LIB) $(SYSTEM)...
	@$(CC) $(DEBUG) $(STANDARD) $(LIBOPT) $(PY2OBJFILES) $(LIBRARY) $(LIBPATHS) -o $(PY2LIB) $(LIBS) $(OTHERLIBS)
	@cp -f src/cmsdk2$(EXTLOW).py $(BINDESTDIR)/

$(PY3LIB): $(LIBRARY) $(PY3OBJFILES)
	@echo Linking $(PY3LIB) $(SYSTEM)...
	@$(CC) $(DEBUG) $(STANDARD) $(LIBOPT) $(PY3OBJFILES) $(LIBRARY) $(LIBPATHS) -o $(PY3LIB) $(LIBS) $(OTHERLIBS) $(PYTHON3LIB)
	@cp -f src/cmsdk3$(EXTLOW).py $(BINDESTDIR)/

############# Cleaning #############

clean:
	@echo Removing .o files and executable
	@find $(BUILDDIR) -path '*/.svn' -prune -o -type f -name \*.[o,d]\* -exec rm -f {} \;
	@rm -rf $(BUILDDIR)
	@rm -f $(PROGRAM) $(LIBRARY) $(PY2LIB) $(PY3LIB) $(BINDESTDIR)/*.py
	@make cleandebug

cleandebug:
	@echo Removing debug .o files and executable
	@find $(BUILDDIR) -path '*/.svn' -prune -o -type f -name \*.[o,d]\* -exec rm -f {} \;
	@rm -rf $(BUILDDIR)
	@rm -f $(PROGRAM) $(LIBRARY) $(PY2LIB) $(PY3LIB) $(BINDESTDIR)/*.py

totalclean : clean
	#@echo Code size before is: `du -ks .`
	@echo Cleaning Visual Studio files...
	@rm -f *.lib
	@find . -type d -name Debug -exec rm -rf {} \; > /dev/null 2>&1
	@find . -type d -name Release -exec rm -rf {} \; > /dev/null 2>&1
	@find . -type f -name \*.ncb -exec rm -f {} \; > /dev/null 2>&1
	@find . -type f -name \*.plg -exec rm -f {} \; > /dev/null 2>&1
	@find . -type f -name \*.exe -exec rm -f {} \; > /dev/null 2>&1
	@find . -type f -name \*.ilk -exec rm -f {} \; > /dev/null 2>&1
	@find . -type f -name \*.vcl -exec rm -f {} \; > /dev/null 2>&1
	@echo Cleaning core dump files...
	@find . -type f -name core -exec rm -f {} \; > /dev/null 2>&1
	#@echo Code size after is: `du -ks .`

############# Open Source Dist #############

licence_files:
	@$(SH) replace.sh YEAR_TEMPLATE "$(YEAR_TODAY)" $(BSD_HEADER_TEMPLATE) $(BSD_HEADER)
	@$(SH) replace.sh DATE_TEMPLATE "$(DATE_TODAY)" $(BSD_HEADER) $(BSD_HEADER)
	@$(SH) replace.sh FULL_VERSION_TEMPLATE "$(VERSION)" $(BSD_HEADER) $(BSD_HEADER)
	
bsd: licence_files
	@rm -rf $(BSDDISTDIR)
	@mkdir $(BSDDISTDIR)

	@echo
	@echo Build date: $(DATE_TODAY) > $(BSDDISTDIR)/version.txt
	@echo CMSDK version $(CMSDK_VERMAJOR).$(CMSDK_VERMINOR).$(CMSDK_REVISION)$(CMSDK_VERSUBTEXT) BSD >> $(BSDDISTDIR)/version.txt
	@echo CMSDK revision $(CMSDK_REVISION) >> $(BSDDISTDIR)/version.txt
	@cat $(BSDDISTDIR)/version.txt
	@echo
	
	@echo Building CMSDK distribution structure
	@$(CPALL) include $(BSDDISTDIR)
	@$(CPALL) src $(BSDDISTDIR)
	@$(CPALL) Makefile $(BSDDISTDIR)
	@$(CPALL) Makefile.sys $(BSDDISTDIR)
	@$(CPALL) Makefile.ver $(BSDDISTDIR)
	@$(CPALL) cmsdk.i $(BSDDISTDIR)
	@$(CPALL) changelog.txt $(BSDDISTDIR)
	@$(CPALL) acknowledgements.txt $(BSDDISTDIR)
	@$(CPALL) *vs2015.vcxproj $(BSDDISTDIR)
	@$(CPALL) *vs2015.sln $(BSDDISTDIR)
	@$(CPALL) *vs2015.vcxproj.filters $(BSDDISTDIR)

	@$(CPALL) $(BSD_LICENCE) $(BSDDISTDIR)

	@echo Inserting BSD licence headers into CMSDK files...
	@find $(BSDDISTDIR) -name \*.h $(DO_NOT_LICENCE_FILES) -exec sh addlicense.sh $(BSD_HEADER) {} \;
	@find $(BSDDISTDIR) -name \*.c $(DO_NOT_LICENCE_FILES) -exec sh addlicense.sh $(BSD_HEADER) {} \;
	@find $(BSDDISTDIR) -name \*.cpp $(DO_NOT_LICENCE_FILES) -exec sh addlicense.sh $(BSD_HEADER) {} \;

	@echo Building archive...
	@zip -qr $(BSDDISTDIR).zip $(BSDDISTDIR)
	
	@echo
	@echo Archive ready: $(BSDDISTDIR).zip - size in kb: `du -ks $(BSDDISTDIR).zip | awk '{print $$1}'`
	@echo
	@exit 0

############# Additional commands #############

rebuild : clean all

run : all
	@echo Running $(PROGNAME)
	@echo
	@$(PROGNAME)

info:
	@echo
	@echo Build date: $(DATE_TODAY)
	@echo CMSDK version $(CMSDK_VERMAJOR).$(CMSDK_VERMINOR).$(CMSDK_REVISION)$(CMSDK_VERSUBTEXT) BSD
	@echo CMSDK revision $(CMSDK_REVISION)
	@echo
