from __future__ import print_function

import json as pyjson
from datetime import datetime
import struct
import os
import argparse, textwrap
import sys
import generate_headers

# 0: Input file path relative to dev folder
# 1: Output file path relative to include folder
# 2: Name of variable
values = [
    ('all_fluids.json','all_fluids_JSON.h','all_fluids_JSON'),
    ('all_incompressibles.json','all_incompressibles_JSON.h','all_incompressibles_JSON'),
    ('mixtures/mixture_excess_term.json', 'mixture_excess_term_JSON.h', 'mixture_excess_term_JSON'),
    ('mixtures/mixture_reducing_parameters.json', 'mixture_reducing_parameters_JSON.h', 'mixture_reducing_parameters_JSON')
]

def TO_CPP(root_dir, hashes):
    def to_chunks(l, n):
        if n<1:
            n=1
        return [l[i:i+n] for i in range(0, len(l), n)]
    
    # Normalise path name
    root_dir = os.path.normpath(root_dir)
    
    # First we package up the JSON files
    import package_json
    package_json.combine_json(root_dir)
    
    for infile,outfile,variable in values:
        
        json = open(os.path.join(root_dir,'dev',infile),'r').read()

        # convert each character to hex and add a terminating NULL character to end the 
        # string, join into a comma separated string
        if sys.version_info[0] == 2:
            h = [hex(struct.unpack("b",b)[0]) for b in json] + ['0x00']
        else:
            # Encode as ASCII characters
            json = json.encode('ascii')
            h = [str(hex(b)) for b in json] + [str('0x00')]
        
        # Break up the file into lines of 16 hex characters
        chunks = to_chunks(h, 16)
        
        # Put the lines back together again
        # The chunks are joined together with commas, and then EOL are used to join the rest
        hex_string = ',\n'.join([', '.join(chunk) for chunk in chunks])
            
        # Check if hash is up to date based on using variable as key
        if variable not in hashes or (variable in hashes and hashes[variable] != generate_headers.get_hash(hex_string)):
        
            # Generate the output string
            output  = '// File generated by the script dev/JSON_to_CPP.py on '+ str(datetime.now()) + '\n\n'
            output += '// JSON file encoded in binary form\n'
            output += 'const unsigned char '+variable+'_binary[] = {\n' + hex_string + '\n};'+'\n\n'
            output += '// Combined into a single std::string \n'
            output += 'std::string {v:s}({v:s}_binary, {v:s}_binary + sizeof({v:s}_binary)/sizeof({v:s}_binary[0]));'.format(v = variable)
            
            # Write it to file
            f = open(os.path.join(root_dir,'include',outfile), 'w')
            f.write(output)
            f.close()
            
            # Store the hash of the data that was written to file (not including the header)
            hashes[variable] = generate_headers.get_hash(hex_string)
        else:
            print(outfile + ' is up to date')

if __name__=='__main__':
    parser = argparse.ArgumentParser(
      formatter_class=argparse.RawDescriptionHelpFormatter,
      description=textwrap.dedent("""CoolProp
      This program converts the JSON files from dev/fluid etc
      to header files. It is necessary to give this program the
      value for --path, this is the root directory where
      dev/ can be found.""")
    )
                       
    parser.add_argument('--path', required=False,
                        help='Location of the root folder',
                        default=None)
                        
    args = parser.parse_args()

    TO_CPP(args.path)