#!/usr/bin/env python3

import  pandas as pd
import  os
import  shutil
import  yaml
import  numpy as np
import  pickle
from    pathlib import Path
import  sys
import  io

class to_paraview:
    """
    This class takes the results from the NI coil model and exports them to something paraview can read.
    """

    # Things it needs from the geometry file:
    positions               = None
    Index_post_inductive    = None
    Index_post_resistive    = None
    Index_post_thermal      = None
    Index_post              = None

    # paths to load
    geometry_yaml_path  = None
    current_path        = None
    temperature_path    = None
    B_grid_path         = None

    # Output
    specific_output_path = None
    paraview_files_to_load = [] # Array with all files that need to be loaded.
    python_files_to_load = dict() # Dictionary with all files that were created per timestep
    python_limits = dict() # Dictionary with the upper and lower limits of the data
    output_file = None

    # Grid
    Bz_full_path = None
    Br_full_path = None
    Bz_full = None
    Br_full = None

    # Values
    current_II_values = None
    current_IR_values = None
    current_I_density_values = None
    temperature_values = None
    B_grid_values = None
    Fz_values = None
    Fr_values = None
    Fz_density_values = None
    Fr_density_values = None
    Bz_values = None
    Br_values = None
    len_entries = None
    Prad_values = None
    Physt_values = None
    Prad_density_values = None
    Physt_density_values = None

    time = []
    max_value = []
    min_value = []

    min = 1e99
    max = -1e99
    minmin = 1e99
    maxmax = -1e99

    angle = 270.0
    npoints = 100

    offset_removal = False

    # Geometry
    nr_of_coils = None

    def __init__(self, results_path, result, angle=270.0, comsol=True, paraview=True, offset_removal=True, npoints = 100):
        """
        INIT
        """

        print('Result:', result)
        print('Angle:', angle)
        print('Comsol bool:', comsol)
        print('Paraview bool:', paraview)
        print('Offset_removal bool:', offset_removal)

        self.reset()

        self.init_path = results_path
        self.parameter = result
        self.angle = angle
        self.offset_removal = offset_removal
        self.npoints = int(npoints)

        self.create_folders()

        self.load_yaml()
        self.load_values()

        if self.len_entries > self.npoints:
            # index_values = np.arange(0, self.len_entries, int(self.len_entries/self.npoints))
            index_values = [i for i in takespread(np.arange(self.len_entries), self.npoints)]
            print(index_values, len(index_values), self.npoints)
        else:
            index_values = np.arange(0, self.len_entries)

        if comsol:
            self.remove_duplicates_save_COMSOL(self.parameter, index_values)

        if paraview:
            for i in range(len(index_values)):
                self.remove_duplicates_save(self.parameter, index_values[i], str(i))
            self.save_python_yaml()

        if 'profiler' in locals():
            profiler.disable()
            s = io.StringIO()
            stats = pstats.Stats(profiler, stream=s).sort_stats('cumulative')
            stats.print_stats(25)
            profiler.dump_stats(self.init_path + os.sep + 'profile_post.pstats')
            with open(self.init_path + os.sep + 'profiler_post.txt', 'w+') as f:
                f.write(s.getvalue())

    def reset(self):
        """
        Resets all parameters to standard. Just in case of shared ref issues.
        :return:
        """
        # Things it needs from the geometry file:
        self.positions = None
        self.Index_post_inductive = None
        self.Index_post_resistive = None
        self.Index_post_thermal = None
        self.Index_post = None

        # paths to load
        self.geometry_yaml_path = None
        self.current_path = None
        self.temperature_path = None
        self.B_grid_path = None

        # Output
        self.specific_output_path = None
        self.paraview_files_to_load = []  # Array with all files that need to be loaded.
        self.python_files_to_load = dict()  # Dictionary with all files that were created per timestep
        self.python_limits = dict()  # Dictionary with the upper and lower limits of the data
        self.output_file = None

        # Grid
        self.Bz_full_path = None
        self.Br_full_path = None
        self.Bz_full = None
        self.Br_full = None

        # Values
        self.current_II_values = None
        self.current_IR_values = None
        self.current_I_density_values = None
        self.temperature_values = None
        self.B_grid_values = None
        self.Fz_values = None
        self.Fr_values = None
        self.Fz_density_values = None
        self.Fr_density_values = None
        self.Bz_values = None
        self.Br_values = None
        self.len_entries = None
        self.Prad_values = None
        self.Physt_values = None
        self.Prad_density_values = None
        self.Physt_density_values = None

        self.time = []
        self.max_value = []
        self.min_value = []

        self.min = 1e99
        self.max = -1e99
        self.minmin = 1e99
        self.maxmax = -1e99

        self.angle = 270.0
        self.npoints = 100
        self.offset_removal = False
        self.nr_of_coils = None

    def load_yaml(self):
        """
        Loads the yaml files.
        """

        # Reads the contents of the yaml file
        with open(self.init_path + os.sep + 'geometry.yaml') as file:
            contents = yaml.load(file, Loader=yaml.FullLoader)

        # Sets the values in the class
        setattr(self, 'positions', contents['positions'])
        setattr(self, 'Index_post_inductive', contents['Index_post_inductive'])
        setattr(self, 'Index_post_resistive', contents['Index_post_resistive'])
        setattr(self, 'Index_post_thermal', contents['Index_post_thermal'])
        setattr(self, 'Index_post', contents['Index_post'])

        self.nr_of_coils = len(self.Index_post)
        self.positions = np.array(self.positions)

    def save_python_yaml(self):
        output_python = {
            'data': self.python_files_to_load,
            'limits': self.python_limits,
            'time': self.time,
            'max_value': self.max_value,
            'min_value': self.min_value,
        }

        with open(self.init_path + os.sep + 'Paraview' + os.sep + "python_files_to_load_" + self.parameter + ".yaml", "w") as f:
            yaml.dump(output_python, f, default_flow_style=False)

    def create_folders(self):
        """
        Generates the output folder.
        :return:
        """
        # Making the output folders
        output_folders = ['COMSOL', 'Paraview']
        for of in output_folders:
            self.make_folder(self.init_path + os.sep + of)
            # Only create folder for the specific parameter being processed
            self.make_folder(self.init_path + os.sep + of + os.sep + self.parameter)
            self.specific_output_path = self.init_path + os.sep + of + os.sep + self.parameter

        self.Bz_full_path = Path(self.init_path).parent.parent.__str__() + os.sep + 'Bz_full.pkl'
        self.Br_full_path = Path(self.init_path).parent.parent.__str__() + os.sep + 'Bz_full.pkl'

    def load_values(self):
        """
        Loading the data values.
        :return:
        """

        if self.parameter == 'II':
            self.current_II_values = pd.read_csv(self.init_path + os.sep + 'current.csv')
            self.len_entries = len(self.current_II_values)
        elif self.parameter == 'IR':
            self.current_IR_values = pd.read_csv(self.init_path + os.sep + 'current_resistor.csv')
            self.len_entries = len(self.current_IR_values)
        elif self.parameter == 'I_density':
            self.current_I_density_values = pd.read_csv(self.init_path + os.sep + 'I_density.csv')
            self.len_entries = len(self.current_I_density_values)
        elif self.parameter == 'Fz':
            self.Fz_values = pd.read_csv(self.init_path + os.sep + 'Fz.csv')
            self.len_entries = len(self.Fz_values)
        elif self.parameter == 'Fr':
            self.Fr_values = pd.read_csv(self.init_path + os.sep + 'Fr.csv')
            self.len_entries = len(self.Fr_values)
        elif self.parameter == 'Fz_density':
            self.Fz_density_values = pd.read_csv(self.init_path + os.sep + 'Fz_density.csv')
            self.len_entries = len(self.Fz_density_values)
        elif self.parameter == 'Fr_density':
            self.Fr_density_values = pd.read_csv(self.init_path + os.sep + 'Fr_density.csv')
            self.len_entries = len(self.Fr_density_values)
        elif self.parameter == 'Bz':
            self.Bz_values = pd.read_csv(self.init_path + os.sep + 'Bz_conductor.csv')
            self.len_entries = len(self.Bz_values)
        elif self.parameter == 'Br':
            self.Br_values = pd.read_csv(self.init_path + os.sep + 'Br_conductor.csv')
            self.len_entries = len(self.Br_values)
        elif self.parameter == 'T':
            self.temperature_values = pd.read_csv(self.init_path + os.sep + 'temperature.csv')
            self.len_entries = len(self.temperature_values)
        elif self.parameter == 'Prad':
            self.Prad_values = pd.read_csv(self.init_path + os.sep + 'Prad.csv')
            self.len_entries = len(self.Prad_values)
        elif self.parameter == 'Physt':
            self.Physt_values = pd.read_csv(self.init_path + os.sep + 'Physt.csv')
            self.len_entries = len(self.Physt_values)
        elif self.parameter == 'Prad_density':
            self.Prad_density_values = pd.read_csv(self.init_path + os.sep + 'Prad_density.csv')
            self.len_entries = len(self.Prad_density_values)
        elif self.parameter == 'Physt_density':
            self.Physt_density_values = pd.read_csv(self.init_path + os.sep + 'Physt_density.csv')
            self.len_entries = len(self.Physt_density_values)


        # Load B_grid files
        try:
            with open(self.Bz_full_path, 'rb') as fin:
                self.Bz_full = pickle.load(fin)
        except OSError:
            print("Loading of %s has failed." % self.Bz_full_path)
        else:
            print("Successfully loaded %s" % self.Bz_full_path)

        # Loading the full magnetic field matrices
        try:
            with open(self.Br_full_path, 'rb') as fin:
                self.Bz_full = pickle.load(fin)
        except OSError:
            print("Loading of %s has failed." % self.Br_full_path)
        else:
            print("Successfully loaded %s" % self.Br_full_path)

        # print(self.current_II_values.iloc[1].values[1:])
        # print(len(self.current_II_values.iloc[1].values[1:]))
        # print(len(self.positions))
        # print(len(self.Index_post))
        # [print(i) for i in self.Index_post]

    def remove_duplicates_save(self, data, iloc, timestep):
        """
        Averages all duplicate points.
        :return:
        """

        self.paraview_files_to_load = []
        python_files_to_load_temp = []
        self.min = 1e99
        self.max = -1e99

        # Loading a timestep
        if data == 'II':
            time = self.current_II_values.iloc[iloc].values[0]
            value = self.current_II_values.iloc[iloc].values[1:]
        elif data == 'IR':
            time = self.current_IR_values.iloc[iloc].values[0]
            value = self.current_IR_values.iloc[iloc].values[1:]
        elif data == 'I_density':
            time = self.current_I_density_values.iloc[iloc].values[0]
            value = self.current_I_density_values.iloc[iloc].values[1:]
        elif data == 'Fz':
            time = self.Fz_values.iloc[iloc].values[0]
            value = self.Fz_values.iloc[iloc].values[1:]
        elif data == 'Fr':
            time = self.Fr_values.iloc[iloc].values[0]
            value = self.Fr_values.iloc[iloc].values[1:]
        elif data == 'Fz_density':
            time = self.Fz_density_values.iloc[iloc].values[0]
            value = self.Fz_density_values.iloc[iloc].values[1:]
        elif data == 'Fr_density':
            time = self.Fr_density_values.iloc[iloc].values[0]
            value = self.Fr_density_values.iloc[iloc].values[1:]
        elif data == 'Bz':
            time = self.Bz_values.iloc[iloc].values[0]
            value = self.Bz_values.iloc[iloc].values[1:]
        elif data == 'Br':
            time = self.Br_values.iloc[iloc].values[0]
            value = self.Br_values.iloc[iloc].values[1:]
        elif data == 'T':
            time = self.temperature_values.iloc[iloc].values[0]
            value = self.temperature_values.iloc[iloc].values[1:]
        elif data == 'Prad':
            time = self.Prad_values.iloc[iloc].values[0]
            value = self.Prad_values.iloc[iloc].values[1:]
        elif data == 'Physt':
            time = self.Physt_values.iloc[iloc].values[0]
            value = self.Physt_values.iloc[iloc].values[1:]
        elif data == 'Prad_density':
            time = self.Prad_density_values.iloc[iloc].values[0]
            value = self.Prad_density_values.iloc[iloc].values[1:]
        elif data == 'Physt_density':
            time = self.Physt_density_values.iloc[iloc].values[0]
            value = self.Physt_density_values.iloc[iloc].values[1:]

        # Printing the time for reference:
        print('Time (s) - Paraview:', time)

        # Data to points
        for coil in range(len(self.Index_post)):
            positions = self.positions[self.Index_post[coil]]
            if data in ['II', 'Fz', 'Fr', 'Bz', 'Br', 'Fr_density', 'Fz_density', 'I_density']:
                value_coil = value[self.Index_post[coil]]
                if self.min > np.min(value_coil): self.min = np.min(value_coil)
                if self.minmin > np.min(value_coil): self.minmin = np.min(value_coil)
                if self.max < np.max(value_coil): self.max = np.max(value_coil)
                if self.maxmax < np.max(value_coil): self.maxmax = np.max(value_coil)
            if data in ['IR', 'T', 'Prad', 'Physt', 'Prad_density', 'Physt_density']:
                value_coil = value[np.array(self.Index_post_thermal)[self.Index_post[coil]]] # TODO changed bracket from [self.Index_post_thermal][self.Index_post[coil]], check if ok
                if self.min > np.min(value_coil): self.min = np.min(value_coil)
                if self.minmin > np.min(value_coil): self.minmin = np.min(value_coil)
                if self.max < np.max(value_coil): self.max = np.max(value_coil)
                if self.maxmax < np.max(value_coil): self.maxmax = np.max(value_coil)

            # df = pd.DataFrame(columns=['x', 'y', 'z', 'v'])
            # n = 0
            # for i in range(len(positions)):
            #     for j in range(4):
            #         # Setting the value on each corner node to value[i]. 'z' is zero.
            #         df.loc[n] = [positions[i][0][j], positions[i][1][j], 0, value_coil[i]]
            #         n+=1

            # The solution proposed by AI, tweaked to make it work.
            num_positions = len(positions)
            num_rows = num_positions * 4  # since there are 4 rows per position

            # Preallocate array: shape (total_rows, 4)
            data_for_df = np.empty((num_rows, 4))
            n = 0

            for i in range(num_positions):
                for j in range(4):
                    data_for_df[n, 0] = positions[i][0][j]  # x
                    data_for_df[n, 1] = positions[i][1][j]  # y
                    data_for_df[n, 2] = 0  # z
                    data_for_df[n, 3] = value_coil[i]  # v
                    n += 1

            # Now create DataFrame all at once
            df = pd.DataFrame(data_for_df, columns=['x', 'y', 'z', 'v'])

            # -> groups by x,y,z -> taking the mean values -> resetting the index to ungroup
            df = df.round({'x': 6, 'y': 6, 'z': 6})
            df_mean = df.groupby(['x', 'y', 'z'], sort=False).mean().reset_index()

            # Saving to csv.
            df_mean.to_csv(self.init_path + os.sep + 'Paraview' + os.sep + data + os.sep + data + '_' + str(coil) + '.' +  timestep.zfill(5) + '.csv', index=False)
            self.paraview_files_to_load.append(self.init_path + os.sep + 'Paraview' + os.sep + data + os.sep + data + '_' + str(coil) + '.' +  timestep.zfill(5) + '.csv')
            python_files_to_load_temp.append(self.init_path + os.sep + 'Paraview' + os.sep + data + os.sep + data + '_' + str(coil) + '.' +  timestep.zfill(5) + '.csv')
        self.python_files_to_load[time.item()] = python_files_to_load_temp
        self.python_limits['minmax'] = [self.minmin.item(), self.maxmax.item()]
        self.time.append(time.item())
        self.max_value.append(self.max.item())
        self.min_value.append(self.min.item())

        # Generate the load state:
        self.generate_python_load_state(timestep)

    def remove_duplicates_save_COMSOL(self, data, iloc_list):
        """
        Averages all duplicate points.
        :return:
        """

        self.paraview_files_to_load = []
        self.min = 1e99
        self.max = -1e99

        # Data to points
        for coil in range(len(self.Index_post)):
            print('COMSOL:', coil)
            positions = self.positions[self.Index_post[coil]]

            if True:
                z_values = []
                for i in range(len(positions)):
                    for j in range(4):
                        z_values.append(positions[i][1][j])
                z_max = np.max(z_values)
                z_min = np.min(z_values)
                z_diff = z_max-z_min
                if self.offset_removal:
                    z_offset = z_max - 0.5*z_diff
                else:
                    z_offset = 0.0

            print('Z offset value (m):', z_offset)

            num_positions = len(positions)
            num_rows = num_positions * 4 * len(iloc_list)  # since you add 4 rows per position

            # Preallocate array: shape (total_rows, 4)
            data_for_df = np.empty((num_rows, 4))

            n = 0

            for iloc in iloc_list:
                # Loading a timestep
                if data == 'II':
                    value_coil = self.current_II_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.current_II_values.iloc[iloc].values[0]
                elif data == 'I_density':
                    value_coil = self.current_I_density_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.current_I_density_values.iloc[iloc].values[0]
                elif data == 'IR':
                    value_coil = self.current_IR_values.iloc[iloc].values[1:][self.Index_post_thermal][self.Index_post[coil]]
                    t = self.current_IR_values.iloc[iloc].values[0]
                elif data == 'Fz':
                    value_coil = self.Fz_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.Fz_values.iloc[iloc].values[0]
                elif data == 'Fr':
                    value_coil = self.Fr_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.Fr_values.iloc[iloc].values[0]
                elif data == 'Fz_density':
                    value_coil = self.Fz_density_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.Fz_density_values.iloc[iloc].values[0]
                elif data == 'Fr_density':
                    value_coil = self.Fr_density_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.Fr_density_values.iloc[iloc].values[0]
                elif data == 'Bz':
                    value_coil = self.Bz_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.Bz_values.iloc[iloc].values[0]
                elif data == 'Br':
                    value_coil = self.Br_values.iloc[iloc].values[1:][self.Index_post[coil]]
                    t = self.Br_values.iloc[iloc].values[0]
                elif data == 'T':
                    value_coil = self.temperature_values.iloc[iloc].values[1:][self.Index_post_thermal][self.Index_post[coil]]
                    t = self.temperature_values.iloc[iloc].values[0]
                elif data == 'Prad':
                    value_coil = self.Prad_values.iloc[iloc].values[1:][self.Index_post_thermal][self.Index_post[coil]]
                    t = self.Prad_values.iloc[iloc].values[0]
                elif data == 'Physt':
                    value_coil = self.Physt_values.iloc[iloc].values[1:][self.Index_post_thermal][self.Index_post[coil]]
                    t = self.Physt_values.iloc[iloc].values[0]
                elif data == 'Prad_densty':
                    value_coil = self.Prad_density_values.iloc[iloc].values[1:][self.Index_post_thermal][self.Index_post[coil]]
                    t = self.Prad_values.iloc[iloc].values[0]
                elif data == 'Physt_densty':
                    value_coil = self.Physt_density_values.iloc[iloc].values[1:][self.Index_post_thermal][self.Index_post[coil]]
                    t = self.Physt_values.iloc[iloc].values[0]


                # This piece of code is really slow and will be improved:
                # for i in range(len(positions)):
                #     for j in range(4):
                #         # Setting the value on each corner node to value[i]. 'z' is zero.
                #         df.loc[n] = [positions[i][0][j], positions[i][1][j]-z_offset, t, value_coil[i]]
                #         n+=1

                # The solution proposed by AI, tweaked to make it work.
                for i in range(num_positions):
                    for j in range(4):
                        data_for_df[n, 0] = positions[i][0][j]  # x
                        data_for_df[n, 1] = positions[i][1][j] - z_offset  # y
                        data_for_df[n, 2] = t  # t
                        data_for_df[n, 3] = value_coil[i]  # value
                        n += 1

            # Now create DataFrame all at once
            df = pd.DataFrame(data_for_df, columns=['r', 'z', 't', 'v'])

            # -> groups by x,y,z -> taking the mean values -> resetting the index to ungroup
            df = df.round({'r': 6, 'z': 6, 't': 6})
            df_mean = df.groupby(['r', 'z', 't'], sort=False).mean().reset_index()

            # Saving to csv.
            df_mean.to_csv(self.init_path + os.sep + 'COMSOL' + os.sep + data + os.sep + data + '_' + str(coil) + '.csv', index=False)

    def generate_python_load_state(self, timestep):
        """
            Generates the load_state python file.
        """
        # Copying the python paraview template
        self.output_file = self.init_path + os.sep + 'Paraview' + os.sep + 'paraview_' + self.parameter + '.' +  timestep.zfill(5) + '.py'
        if os.path.isfile(self.output_file): os.remove(self.output_file)
        shutil.copy(os.getcwd() + os.sep + 'utils' + os.sep + 'paraview_template.py', self.output_file)

        with open(self.output_file, "a+") as f:
            for i in range(len(self.paraview_files_to_load)):
                f.write('# create a new "CSV Reader"\n')
                f.write('test_' + str(i) + 'csv = CSVReader(registrationName="data' + str(i) + '", FileName=[\'' + self.paraview_files_to_load[i] + '\'])\n\n')

                f.write('# create a new "Table To Points"\n')
                f.write('tableToPoints' + str(i) + ' = TableToPoints(registrationName="TableToPoints' + str(i) + '", Input=test_' + str(i) + 'csv)\n')
                f.write('tableToPoints' + str(i) + '.XColumn = \'x\'\n')
                f.write('tableToPoints' + str(i) + '.YColumn = \'y\'\n')
                f.write('tableToPoints' + str(i) + '.ZColumn = \'z\'\n\n')

                f.write('# create a new "Delaunay 2D"\n')
                f.write('delaunay2D' + str(i) + ' = Delaunay2D(registrationName=\'Delaunay2D' + str(i) +'\', Input=tableToPoints' + str(i) + ')\n\n')

                f.write('# create a new \'Reflect\'\n')
                f.write('reflect' + str(i) + ' = Reflect(registrationName=\'Reflect' + str(i) + '\', Input=delaunay2D' + str(i) + ')\n')
                f.write('reflect' + str(i) + '.Plane = \'X\'\n')

                f.write('# create a new "Rotational Extrusion"\n')
                f.write('rotationalExtrusion' + str(i) + ' = RotationalExtrusion(registrationName=\'RotationalExtrusion' + str(i) + '\', Input=delaunay2D' + str(i) + ')\n')
                f.write('rotationalExtrusion' + str(i) + '.Resolution = 48\n')
                f.write('rotationalExtrusion' + str(i) + '.Angle = ' + str(self.angle) + '\n')
                f.write('rotationalExtrusion' + str(i) + '.RotationAxis = [0.0, 1.0, 0.0]\n\n')


        with open(self.output_file, "a+") as f:
            for i in range(len(self.paraview_files_to_load)):
                f.write('rotationalExtrusion' + str(i) + 'Display = Show(rotationalExtrusion' + str(i) + ', renderView1, \'GeometryRepresentation\')\n')
                f.write('rotationalExtrusion' + str(i) + 'Display.SetScalarBarVisibility(renderView1, True)\n\n')


            f.write('# get 2D transfer function for \'v\'\n')
            f.write('vTF2D = GetTransferFunction2D(\'v\')\n')
            f.write('# get color transfer function/color map for \'v\'\n')
            f.write('vLUT = GetColorTransferFunction(\'v\')\n')
            f.write('vLUT.TransferFunction2D = vTF2D\n')
            f.write('vLUT.RGBPoints = [' + str(self.min) + ', 0.231373, 0.298039, 0.752941, ' + str((self.min+self.max)/2.0) + ', 0.865003, 0.865003, 0.865003, ' + str(self.max) + ', 0.705882, 0.0156863, 0.14902]\n')
            f.write('vLUT.ScalarRangeInitialized = 1.0\n\n')

            for i in range(len(self.paraview_files_to_load)):
                f.write('# trace defaults for the display properties.\n')
                f.write('rotationalExtrusion' + str(i) + 'Display.Representation = \'Surface\'\n')
                f.write('rotationalExtrusion' + str(i) + 'Display.ColorArrayName = [\'POINTS\', \'v\']\n')
                f.write('rotationalExtrusion' + str(i) + 'Display.LookupTable = vLUT\n')
                f.write('rotationalExtrusion' + str(i) + 'Display.Opacity = 0.60\n\n')

            f.write('# show data from delaunay2D\n')
            for i in range(len(self.paraview_files_to_load)):
                f.write('delaunay2D' + str(i) + 'Display = Show(delaunay2D' + str(i) + ', renderView1, \'GeometryRepresentation\')\n')
                f.write('delaunay2D' + str(i) + 'Display.Representation = \'Surface\'\n')
                f.write('delaunay2D' + str(i) + 'Display.ColorArrayName = [\'POINTS\', \'v\']\n')
                f.write('delaunay2D' + str(i) + 'Display.LookupTable = vLUT\n')
                f.write('delaunay2D' + str(i) + 'Display.ScaleTransferFunction.Points = [' + str(self.min) + ', 0.0, 0.5, 0.0, ' + str(self.max) + ', 1.0, 0.5, 0.0]\n') # [Min, 0.0, 0.5, 0.0, Max, 1.0, 0.5, 0.0]
                f.write('delaunay2D' + str(i) + 'Display.OpacityTransferFunction.Points = [' + str(self.min) + ', 0.0, 0.5, 0.0, ' + str(self.max) + ', 1.0, 0.5, 0.0]\n') # [Min, 0.0, 0.5, 0.0, Max, 1.0, 0.5, 0.0]
                f.write('delaunay2D' + str(i) + 'Display.SetScaleArray = [\'POINTS\', \'v\']\n')
                f.write('delaunay2D' + str(i) + 'Display.ScaleTransferFunction = \'PiecewiseFunction\'\n')
                f.write('delaunay2D' + str(i) + 'Display.OpacityArray = [\'POINTS\', \'v\']\n')
                f.write('delaunay2D' + str(i) + 'Display.OpacityTransferFunction = \'PiecewiseFunction\'\n')
                f.write('delaunay2D' + str(i) + 'Display.SetScalarBarVisibility(renderView1, True)\n\n')


            # Legend
            f.write('# get color legend/bar for vLUT in view renderView1\n')
            f.write('vLUTColorBar = GetScalarBar(vLUT, renderView1)\n')
            f.write('vLUTColorBar.Title = \'v\'\n')
            f.write('vLUTColorBar.ComponentTitle = \'\'\n')
            f.write('# set color bar visibility\n')
            f.write('vLUTColorBar.Visibility = 1\n\n')


        # Output render
        with open(self.output_file, "a+") as f:
            f.write('# ----------------------------------------------------------------\n')
            f.write('# setup the visualization in view \'renderView1\'\n')
            f.write('# ----------------------------------------------------------------\n\n')

            # get opacity transfer function/opacity map for 'v'
            f.write('vPWF = GetOpacityTransferFunction(\'v\')\n')
            f.write('vPWF.Points = [' + str(self.min) + ', 0.0, 0.5, 0.0, ' + str(self.max) + ', 1.0, 0.5, 0.0]\n')
            f.write('vPWF.ScalarRangeInitialized = 1\n\n')

        # At the end of the file:
        with open(self.output_file, "a+") as f:
            f.write('if __name__ == \'__main__\':\n')
            f.write('\t# generate extracts\n')
            f.write('\tSaveExtracts(ExtractsOutputDirectory=\'extracts\')\n')

    def generate_python_load_state_B_grid(self):
        """
        Creates the stream + contour plot for the magnetic field.
        """
        x = 1


    @staticmethod
    def make_folder(path):
        try:
            os.mkdir(path)
        except OSError:
            print("Creation of the directory %s failed" % path)
        else:
            print("Successfully created the directory %s " % path)


def str_to_bool(s):
    if s in ['True', 'true']:
         return True
    elif s in ['False', 'false']:
         return False
    else:
         raise ValueError

def takespread(sequence, num):
    length = float(len(sequence))
    for i in range(num):
        yield sequence[int(np.ceil(i * length / num))]

if __name__ == "__main__":
    print(sys.argv)
    print('Starting profiler')
    import cProfile, pstats
    profiler = cProfile.Profile()
    profiler.enable()
    if len(sys.argv) >= 6:
        print('Loading from runner.')
        print(sys.argv)
        TP = to_paraview(sys.argv[1], sys.argv[2], float(sys.argv[3]), str_to_bool(sys.argv[4]), str_to_bool(sys.argv[5]), str_to_bool(sys.argv[6]), int(sys.argv[7]))
