import os
import json
import time
import pickle
import sys

import matplotlib.pyplot as plt


from binarycpython.utils.grid import Population
from binarycpython.utils.functions import get_help_all, get_help

## Script is intended for some testing of grid functionality. Its a bit random, not really structured tbh


test_pop = Population()

## Setting values
# print(test_pop.bse_options['M_1'])
# print(test_pop.bse_options['M_2'])
# test_pop.set(M_1=10, M_2=500)
# print(test_pop.bse_options['M_1'])
# print(test_pop.bse_options['M_2'])
test_pop.set(
    M_1=10,
    separation=0,
    orbital_period=4580,
    max_evolution_time=15000,
    eccentricity=0.02,
)
# print(test_pop.bse_options)

## Testing single evolution
# test_pop.evolve_single()
# test_pop.test_evolve_single()

## Setting custom value
# test_pop.set(data_dir=os.path.join(os.environ['BINARYC_DATA_ROOT'], 'development_example'))
# print(test_pop.custom_options['data_dir'])

## printing all options
# print(json.dumps(test_pop.return_population_settings(), indent=4))

## return arglines:
# test_pop.set(M_1=10, M_2=500)
# print(test_pop.return_argline())
# test_pop.return_argline()

## return version info
# version_info = test_pop.return_binary_c_version_info()
# print(version_info)


## Use custom arg file
# test_pop.evolve_population(custom_arg_file='/home/david/projects/binary_c_root/binary_c-python/tests/population/custom_arg_file.txt')

## Custom logging:
# test_pop.set(C_auto_logging={'MY_HEADER_LINE': ['star[0].mass', 'star[1].mass', 'model.probability']})
# test_pop.set(C_logging_code='Printf("MY_STELLAR_DATA time=%g mass=%g radius=%g\\n", stardata->model.time, stardata->star[0].mass, stardata->star[0].radius);')
# test_pop.evolve_population()


## Custom logging with bigger print statement:
test_pop.set(M_1=100, M_2=1, metallicity=0.0002, orbital_period=500000000)
test_pop.set(
    C_logging_code="""
    if(stardata->star[0].stellar_type>=MS)
    {
        if (stardata->model.time < stardata->model.max_evolution_time)
        {
            Printf("DAVID_SCO %30.12e %g %g %g %g %d %d\\n",
                // 
                stardata->model.time, // 1

                stardata->star[0].mass, //2
                stardata->previous_stardata->star[0].mass, //3

                stardata->star[0].radius, //4
                stardata->previous_stardata->star[0].radius, //5

                stardata->star[0].stellar_type, //6
                stardata->previous_stardata->star[0].stellar_type //7
          );
        };
        /* Kill the simulation to save time */
        // stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
    };
"""
)
# test_pop.evolve_population()


## Help all
# print(get_help_all(return_dict=True))

# get_help_all()
# print(get_help('M_1', print_help=False, return_dict=True))


## return all info:
# print(json.dumps(test_pop.return_all_info(), indent=4))
# test_pop.export_all_info(outfile=os.path.join(os.getcwd(), "test_output.txt"))

################# Parse function
## Testing some stuff out with giving a parse_function. 
test_pop.set(
    C_logging_code="""
    if(stardata->star[0].stellar_type>=NS)
    {
        if (stardata->model.time < stardata->model.max_evolution_time)
        {
            Printf("DAVID_SCO %30.12e %g %g %g %g %d %d\\n",
                // 
                stardata->model.time, // 1

                stardata->star[0].mass, //2
                stardata->previous_stardata->star[0].mass, //3

                stardata->star[0].radius, //4
                stardata->previous_stardata->star[0].radius, //5

                stardata->star[0].stellar_type, //6
                stardata->previous_stardata->star[0].stellar_type //7
          );
        };
        /* Kill the simulation to save time */
        stardata->model.max_evolution_time = stardata->model.time - stardata->model.dtm;
    };
"""
)


def output_lines(output):
    """
    Function that outputs the lines that were recieved from the binary_c run. 
    """
    return output.splitlines()

def parse_function(self, output):
    # extract info from the population instance
    # TODO: think about whether this is smart. Passing around this object might be an overkill

    # Get some information from the 
    data_dir = self.custom_options['data_dir']
    base_filename = self.custom_options['base_filename']
    outfilename = os.path.join(data_dir, base_filename)

    # TODO: make population settings available in this function
    for el in output_lines(output):
        headerline = el.split()[0]

        if (headerline=='DAVID_SCO'):
            parameters = ['time', 'mass_1', 'prev_mass_1', 'radius_1', 'prev_radius_1', 'stellar_type_1', 'prev_stellar_type_1']
            values = el.split()[1:]
            seperator='\t'

            if not os.path.exists(outfilename):
                with open(outfilename, 'w') as f:
                    f.write(seperator.join(parameters)+'\n')

            with open(outfilename, 'a') as f:
                f.write(seperator.join(values)+'\n')


#test_pop.evolve_single(parse_function)
test_pop.set(M_1=90, data_dir=os.path.join(os.environ['BINARYC_DATA_ROOT'], 'testing_python'), base_filename='test_pop.dat')
test_pop.evolve_single(parse_function)
test_pop.set(M_1=80)
test_pop.evolve_single(parse_function)
test_pop.set(M_1=70)
test_pop.evolve_single(parse_function)
test_pop.set(M_1=60)
test_pop.evolve_single(parse_function)

##################
## CHeck size of commands:
## Using pickle to dump it.
## https://stackoverflow.com/questions/563840/how-can-i-check-the-memory-usage-of-objects-in-ipython/565382#565382

# def generate_commands_return_size(amt_systems):
#     print("Doing {} systems".format(amt_systems))
#     start_generate_time = time.time()
#     commands = [test_pop.return_argline() for el in range(amt_systems)]
#     stop_generate_time = time.time()

#     size = sys.getsizeof(pickle.dumps(commands))
#     size_in_mb = size/(1024*1024)
#     return size_in_mb

# amounts = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000]
# sizes = []
# for amount in amounts:
#     sizes.append(generate_commands_return_size(amount))


# plt.title('size scaling for binary_c commands with:\n`{}`'.format(test_pop.return_argline()))
# plt.plot(amounts, sizes, 'bo', label='MB for ')
# plt.legend()
# plt.xlabel("Amount of systems")
# plt.ylabel("Size in MB")
# plt.xscale('log')
# plt.yscale('log')
# plt.savefig('sizes_for_commands.png')
# plt.show()