"""
==============================
Histogram Plot Module 
==============================

This module provides comprehensive tools for generating statistical histograms and probability density distributions of meteorological observational data. It enables users to visualize the statistical behavior of residuals, assess data normality, and evaluate systemic biases in CMC (Canadian Meteorological Centre) datasets through Gaussian curve fitting.

Overview
--------

the ``histogram`` module visualizes *how* the data values are distributed. It computes the frequency or probability density of residuals (e.g., Observation minus Prediction) across specified regions, families, and channels. These visualizations are critical for verifying assumption of Gaussian error distributions in data assimilation schemes.

Key Features
------------

* **Distribution Analysis**: Visualizes the spread, central tendency, and skewness of observation residuals using robust step-plot histograms.
* **Gaussian Curve Fitting**: Automatically calculates the weighted mean ($\mu$) and standard deviation ($\sigma$) to overlay a mathematically fitted Gaussian (normal) probability density curve.
* **Peak-Amplitude Scaling**: Intelligently scales ideal mathematical curves to physically align with raw observation counts (N) for intuitive visual comparison.
* **Comparative Overlays**: Enables direct visual comparison of Control vs. Evaluation datasets by overlaying transparent distributions on a single, unified axis.

Supported Metrics
-----------------

omp (Observation minus Prediction)
    Distribution of the differences between observed values and model background. Crucial for identifying systematic background biases (shifts from zero) and overall variance.

    .. image:: _static/hist_omp1.png
       :alt: OMP Histogram Plot
       :align: center


Usage & Command-Line Parameters
-------------------------------

.. tip::
   **Interactive Session Setup:** Extracting high-resolution bins from SQLite databases across massive global datasets can be memory-intensive. Starting an interactive session is recommended:
   
   .. code-block:: bash
   
       qsub -I -X -l select=1:ncpus=20:mem=64gb -l place=scatter -l walltime=2:0:0

Below is the list of parameters available when calling ``pikobs.histogram.arg_call()``:

``--path_experience_files``
    Absolute path to the input data directory for the experiment.
``--experience_name``
    Name or identifier of the experiment (e.g., ``GIC5DA1E22_DDT2``).
``--pathwork``
    Working directory where output PNG plots and intermediate SQLite databases will be saved.
``--datestart`` / ``--dateend``
    Start and end dates for the analysis (``YYYYMMDDHH`` format).
``--region``
    Geographical bounding box filtering the data (e.g., ``Monde``, ``Ameriques``).
``--family``
    Observation instrument family to process (e.g., ``atms_allsky``, ``sw``).
``--flags_criteria``
    Quality control bitmask filter (e.g., ``assimilee``).
``--fonction``
    Space-separated list of metrics to compute as histograms (e.g., ``omp oma bcorr``).
``--id_stn``
    Station ID selection behavior (``all``, ``join``, or specific ID like ``METOP-1``).
``--channel``
    Satellite channel selection (``all``, ``join``, or specific channel like ``11003``).

Single Experiment Analysis
--------------------------

Generate a probability distribution histogram for a single experiment focusing on assimilated METOP-1 observations:

.. code-block:: bash

    python -c 'import pikobs; pikobs.histogram.arg_call()' \

         --path_experience_files  /home/dlo001/sites8/Data_pikobs/monitoring0/ \\
         --experience_name        GIC5DA1E22_DDT2 \\
         
         --pathwork               /home/dlo001/sites8/Data_pikobs1_hist \\
         
         --datestart              2026020100 \\
         
         --dateend                2026020200 \\
         
         --region                 Monde \\
         
         --family                 sw \\
         
         --flags_criteria         assimilee \\
         
         --fonction               omp \\
         
         --id_stn                 METOP-1 \\
         
    

**What this command does:**
Processes assimilated data for the ``sw`` family, specifically for station ``METOP-1`` . It computes the distribution of ``omp`` residuals, plotting the raw frequency step-plot alongside a fitted Gaussian curve detailing the total observation count (N), mean ($\mu$), and standard deviation ($\sigma$).

Comparative Analysis (Control vs. Evaluation)
---------------------------------------------

To evaluate the impact of a new experimental run, Pikobs can overlay the residual distributions of an evaluation experiment directly on top of a control run.

.. code-block:: bash

    python -c 'import pikobs; pikobs.histogram.arg_call()' \\
         
         --path_control_files     /home/dlo001/sites8/Data_pikobs/monitoring0/ \\
         
         --control_name           control \\
         
         --path_experience_files  /home/dlo001/sites8/Data_pikobs/monitoring1/ \\
         
         --experience_name        experience \\
         
         --pathwork               /home/dlo001/sites8/Data_pikobs1_comparative \\
         
         --datestart              2026020100 \\
         
         --dateend                2026020200 \\
         
         --region                 Monde \\
         
         --family                 sw \\
         
         --flags_criteria         assimilee \\
         
         --fonction               omp oma \\
         
         --id_stn                 METOP-1 \\


**What this command does:**
Extracts the bin arrays from both the ``control`` and ``experience`` databases. It plots both histograms on the same axes using semi-transparent colors (alpha blending). 

Comparative Visualizations
~~~~~~~~~~~~~~~~~~~~~~~~

Unlike the ``scatter`` module which plots spatial differences side-by-side, the ``histogram`` module excels at overlapping comparisons.

.. note::
   **Interpreting Comparative Overlays:** When comparing a new Evaluation Experiment against a Control:
   
   * **Taller & Narrower Curve:** A smaller standard deviation ($\sigma$). This generally indicates an improvement, as errors (residuals) are more tightly clustered around the mean.
   * **Shifted Curve:** A change in the mean ($\mu$). A curve moving closer to 0.0 indicates a reduction in systematic bias.

Outputs & Performance Notes
---------------------------

Upon successful execution, the module generates:

* **Histogram Plots**: High-quality PNG images featuring clear, full bounding boxes and external dual-column legends, optimized for scientific reports.
* **Gaussian Metadata**: Integrated $\mu$, $\sigma$, and N values directly on the plot.


Support & Troubleshooting
-------------------------

If you encounter any issues, experience unexpected behavior, or have feature requests while using the ``histogram`` module, please open an issue in the `Pikobs GitLab Repository <https://gitlab.science.gc.ca/dlo001/Pikobs>`_. 

*Please include your exact command, parameters, and error logs when reporting an issue.*



"""

#/usr/bin/python3
import sqlite3
import re
import os
from datetime import datetime, timedelta
from typing import List, Dict, Any, Tuple
import warnings

import numpy as np
from dask.distributed import Client
import shapely
import cartopy

import pikobs

# Suppress Shapely deprecation warnings
warnings.filterwarnings("ignore", ".*ShapelyDeprecationWarning.*")
def create_table_if_not_exists(cursor, extra_sw):
    """
    Create the 'serie_cardio' table if it does not already exist.

    Args:
        cursor (sqlite3.Cursor): Database cursor for executing SQL queries.
    """
    query = f"""
        CREATE TABLE IF NOT EXISTS moyenne (
            Nrej INTEGER,
            Nacc INTEGER,
            Nprofile INTEGER,
            DATE INTEGER,
            lat FLOAT,
            lon FLOAT,
            boite INTEGER,
            id_stn TEXT,
            varno INTEGER,
            vcoord FLOAT,   -- INTEGER FLOAT canal
            sumx FLOAT,
            sumy FLOAT,
            sumz FLOAT,
            sumStat FLOAT,
            sumx2 FLOAT,
            sumy2 FLOAT,
            sumz2 FLOAT,
            sumStat2 FLOAT,
            n INTEGER,
            flag INTEGER
            {extra_sw}
        ); """
    cursor.execute(query)

import sqlite3
import re
import os

import sqlite3
import re
import os

import sqlite3
import re
import os

import sqlite3
import re
import os

import sqlite3
import re
import os

def create_and_populate_moyenne_table(
    family,
    new_db_filename: str,
    existing_db_filename: str,
    selected_region,
    selected_flags, 
    FUNCTION,      
    boxsizex: float, 
    boxsizey: float, 
    varnos,
    channel: str,
    id_stn: str,
    interval
) -> None:
    print (new_db_filename)
    # We connect directly to the PHYSICAL file so the data persists
    with sqlite3.connect(new_db_filename, timeout=99999) as conn:
        cursor = conn.cursor()

        # Performance PRAGMAs for the physical file
        cursor.execute("PRAGMA journal_mode = WAL;") # WAL is better for parallel access
        cursor.execute("PRAGMA synchronous = OFF;")

        # 1. Ensure the final table exists in the physical file
        cursor.execute("""
            CREATE TABLE IF NOT EXISTS moyenne (
                chan TEXT,
                id_stn TEXT,
                varno TEXT,
                vcoord REAL,
                bin_range REAL,
                omp_frequency INTEGER,
                oma_frequency INTEGER
            );
        """)

        # 2. Attach the SOURCE database
        cursor.execute(f"ATTACH DATABASE '{existing_db_filename}' AS db;")

        # 3. Pikobs criteria
        FAM, VCOORD, VCOCRIT, STATB, element, VCOTYP = pikobs.family(family)
        element = ",".join(varnos) if varnos else element
        flag_criteria = pikobs.flag_criteria(selected_flags)

        # 4. Selection/Grouping Logic
        if channel == 'join' and id_stn == 'all':
            chan_select, id_stn_select = '"join"', 'id_stn'
            group_by = 'GROUP BY bin_range, id_stn, varno'
        elif channel == 'all' and id_stn == 'join':
            chan_select, id_stn_select = f'{VCOORD}', '"join"'
            group_by = f'GROUP BY bin_range, {VCOORD}, varno, vcoord'
        elif channel == 'all' and id_stn == 'all':
            chan_select, id_stn_select = f'{VCOORD}', 'id_stn'
            group_by = f'GROUP BY bin_range, id_stn, {VCOORD}, varno, vcoord'
        else:
            chan_select, id_stn_select = '"join"', '"join"'
            group_by = 'GROUP BY bin_range, varno'

        int_a, int_b = interval
        interval_criteria = f"AND vcoord >= {int_a*100} AND vcoord <= {int_b*100}" if int_a is not None else ""

        # 5. Insert directly from the attached DB into the physical table
        # Using rowid for the JOIN as discussed
        qu=f"""
            INSERT INTO moyenne (chan, id_stn, varno, vcoord, bin_range, omp_frequency, oma_frequency)
            SELECT 
                {chan_select},
                {id_stn_select},
                varno,
                vcoord,
                FLOOR(val / 0.1) * 0.1 AS bin_range,
                SUM(CASE WHEN source = 'omp' THEN 1 ELSE 0 END),
                SUM(CASE WHEN source = 'oma' THEN 1 ELSE 0 END)
            FROM (
                SELECT omp AS val, 'omp' AS source, varno, flag, vcoord, id_stn, {VCOORD} 
                FROM db.DATA 
                JOIN db.HEADER ON db.DATA.rowid = db.HEADER.rowid
                UNION ALL
                SELECT oma AS val, 'oma' AS source, varno, flag, vcoord, id_stn, {VCOORD} 
                FROM db.DATA 
                JOIN db.HEADER ON db.DATA.rowid = db.HEADER.rowid
            ) AS combined
            WHERE varno IN ({element}) 
              {flag_criteria}
              {VCOCRIT}
              {interval_criteria}
            {group_by};
        """
        cursor.execute(qu)
        conn.commit()
        cursor.execute("DETACH DATABASE db;")

def combine(pathfileout: str, filememory: str) -> None:
    with sqlite3.connect(pathfileout, timeout=9999) as conn:
        try:
            conn.execute("PRAGMA journal_mode = OFF;")
            conn.execute("PRAGMA synchronous = OFF;")

            conn.execute("""
                CREATE TABLE IF NOT EXISTS histogram_results (
                    chan TEXT,
                    id_stn TEXT,
                    varno TEXT,
                    vcoord REAL,
                    bin_range REAL,
                    omp_frequency INTEGER,
                    oma_frequency INTEGER
                );
            """)

            conn.execute(f"ATTACH DATABASE '{filememory}' AS mem_db;")
            conn.execute("""
                INSERT INTO histogram_results (chan, id_stn, varno, vcoord, bin_range, omp_frequency, oma_frequency)
                SELECT chan, id_stn, varno, vcoord, bin_range, omp_frequency, oma_frequency
                FROM mem_db.histogram_results;
            """)
            conn.commit()
            conn.execute("DETACH DATABASE mem_db;")
        except sqlite3.Error as e:
            print(f"Error in combine: {e}")
            raise
import sqlite3
import re
import os
# import pikobs
# from tu_modulo import combine



def create_data_list(
    date_start: str,
    date_end: str,
    families: List[str],
    input_paths: List[str],
    names: List[str],
    work_path: str,
    box_size_x: float,
    box_size_y: float,
    function: str,
    flag_criteria: str,
    regions: List[Any],       # adjust type if you have a region class
    varnos: List[str],
    intervals: List[Tuple[Any, Any]],
) -> List[Dict[str, Any]]:
    """
    Builds a list of dictionaries containing all configuration info 
    for data processing at 6-hour intervals, for multiple families, 
    regions, input files, and intervals.

    Args:
        date_start (str): Start date string in format 'YYYYMMDDHH'.
        date_end (str): End date string in format 'YYYYMMDDHH'.
        families (List[str]): List of family names/codes.
        input_paths (List[str]): List of input file path prefixes.
        names (Lis./t[str]): List of dataset names.
        work_path (str): Path where output databases should be created.
        box_size_x (float): Size of the box in longitude.
        box_size_y (float): Size of the box in latitude.
        function (str): Function being applied (name/purpose).
        flag_criteria (str): Flag criteria (as a code or query substring).
        regions (List[Any]): List of region specifications.
        varnos (List[str]): List of variable numbers/codes.
        intervals (List[Tuple[Any, Any]]): List of interval tuples (min, max).

    Returns:
        List[Dict[str, Any]]: List of configuration dictionaries.
    """
    data_list = []

    dt_start = datetime.strptime(date_start, '%Y%m%d%H')
    dt_end = datetime.strptime(date_end, '%Y%m%d%H')
    delta = timedelta(hours=6)
    current_date = dt_start

    while current_date <= dt_end:
        formatted_date = current_date.strftime('%Y%m%d%H')
        # Nested loops over all combinations
        for family in families:
            for region in regions:
                for name, input_path in zip(names, input_paths):
                    for interval in intervals:
                        interval_a, interval_b = interval
                        if interval_a is None and interval_b is None:
                            layers = 'layer_all'
                        else:
                            layers = f'layer_from{interval_a}MPato{interval_b}MPa'

                        filename = f'{formatted_date}_{family}'
                        filein = f'{input_path}/{filename}'
                        db_new = (
                            f'{work_path}/{family}/scatter_{name}_{region}_'
                            f'{date_start}_{date_end}_'
                            f'{flag_criteria}_{family}.db'
                        )

                        data_dict = {
                            'family': family,
                            'filein': filein,
                            'db_new': db_new,
                            'region': region,
                            'flag_criteria': flag_criteria,
                            'function': function,
                            'boxsizex': box_size_x,
                            'boxsizey': box_size_y,
                            'varnos': varnos,
                            'interval': interval
                        }
                        data_list.append(data_dict)
        current_date += delta

    return data_list   
   
import sqlite3
import numpy as np

def get_id_stns(cursor, id_stn, WIND_COMP_METHOD):
    """Obtiene la lista de id_stn desde la base de datos."""
  #  print (id_stn, WIND_COMP_METHOD)
    if id_stn == 'all' and WIND_COMP_METHOD:
        #print ('a')
        query = "SELECT DISTINCT id_stn, WIND_COMP_METHOD FROM moyenne;"
        cursor.execute(query)
        return np.array(cursor.fetchall())

    if id_stn == 'all' and WIND_COMP_METHOD != True:
       # print ('b')
        query = "SELECT DISTINCT id_stn FROM moyenne;"
        cursor.execute(query)
        rows = cursor.fetchall()
        return np.array([[row[0], None] for row in rows])
    if id_stn == 'join' and WIND_COMP_METHOD == True:
      #  print ('c')
        query = "SELECT DISTINCT WIND_COMP_METHOD FROM moyenne;"
        cursor.execute(query)
        rows = cursor.fetchall()
        return np.array([['join',row[0]] for row in rows])


    return [('join', x) for x in [None, None]]

def fetch_vcoords(cursor, criter):
    """Obtiene las coordenadas verticales y números de variable según el criterio dado."""
    query = f"SELECT DISTINCT vcoord, varno FROM moyenne {criter} ORDER BY vcoord ASC;"
    cursor.execute(query)
    return cursor.fetchall()

def fetch_channels_varno(cursor):
    """Obtiene los números de variable de todos los canales."""
    query = "SELECT DISTINCT varno FROM moyenne ORDER BY vcoord ASC;"
    cursor.execute(query)
    return [item[0] for item in cursor.fetchall()]

import pandas as pd # Si no tienes pandas, avísame y lo hacemos con strings

import os
import sqlite3
import pandas as pd

import sqlite3
import os
import pandas as pd


import sqlite3
import os
import pandas as pd

import sqlite3
import os
import pandas as pd

def create_data_list_plot(
    date_start, date_end, families, nameins, work_path, 
    box_size_x, box_size_y, flag_criteria, 
    regions, id_stn, channel, projections
) -> list:
    data_list_plot = []
    
    # Normalizar funciones y proyecciones
    plot_projs = [projections] if isinstance(projections, str) else (projections or ['none'])


    for family in families:
            for region in regions:
                # Nombre del archivo
                filename = f"scatter_{nameins[0]}_{region}_{date_start}_{date_end}_{flag_criteria}_{family}.db"
                
                # Intentar ruta con subcarpeta 'sw'
                filepath1 = os.path.join(work_path, family, filename)
                files_in=[filepath1]
                if len(nameins)>1:
                    filename = f"scatter_{nameins[1]}_{region}_{date_start}_{date_end}_{flag_criteria}_{family}.db"
                
                    # Intentar ruta con subcarpeta 'sw'
                    filepath2 = os.path.join(work_path, family, filename)
               
                    files_in=[filepath1,filepath2]

                # DEBUG: Esto te dirá qué está buscando el script


                try:
                    with sqlite3.connect(files_in[0]) as conn:
                        cursor = conn.cursor()
                        
                        # DEBUG: Verificar tablas disponibles
                        cursor.execute("SELECT name FROM sqlite_master WHERE type='table'")
                        tablas = [t[0] for t in cursor.fetchall()]
                        
                        if 'moyenne' not in tablas:
                            print(f"! ERROR: El archivo tiene tablas {tablas}, pero NO 'moyenne'")
                            continue

                        id_stns = get_id_stns(cursor, id_stn, False) 
                        
                        for idstn, _ in id_stns:
                            if channel == 'all':
                                where = f'WHERE id_stn = "{idstn}"' if id_stn != 'join' else ''
                                targets = fetch_vcoords(cursor, where) 
                            else:
                                targets = [('join', v) for v in fetch_channels_varno(cursor)]

                            for vcoord, varno in targets:
                                    for proj in plot_projs:
                                        data_list_plot.append({
                                            'family': family, 'region': region, 'id_stn': idstn,
                                            'vcoord': vcoord, 'varno': varno, 
                                            'proj': proj, 'files_in': files_in
                                        })
                except Exception as e:
                    print(f"!! Error abriendo DB: {e}")

    # Imprimir tabla si hay resultados
    if data_list_plot:
        df = pd.DataFrame(data_list_plot)
        print(df[['family','vcoord' ,'region', 'id_stn', 'varno']].drop_duplicates().to_string(index=False))
        print(f"\nTOTAL: {len(df)} plots")
    
    return data_list_plot

def make_histogram(files_in,
                 names_in,  
                 pathwork, 
                 datestart,
                 dateend,
                 regions, 
                 families, 
                 flag_criteria, 
                 fonctions, 
                 varnos,
                 boxsizex, 
                 boxsizey, 
                 projs, # Proj=='OrthoN'// Proj=='OrthoS'// Proj=='robinson' // Proj=='Europe' // Proj=='Canada' // Proj=='AmeriqueNord' // Proj=='Npolar' //  Proj=='Spolar' // Proj == 'reg'
                 mode,
                 Points,
                 id_stn,
                 channel,
                 n_cpu,
                 intervales):
   
        """
       Perform scatter plot generation based on input parameters.
   
       Args:

        files_in (list): List of input file paths.

        names_in (list): List of input file names.

        pathwork (str): Working directory.

        datestart (str): Start date in YYYYMMDDHH format.

        dateend (str): End date in YYYYMMDDHH format.

        region (str): Region parameter description.

        family (str): Family parameter description.

        flag_criteria (str): Flags criteria.

        fonction (str): Function parameter description.

        boxsizex (int): Box size in X direction.

        boxsizey (int): Box size in Y direction.

        Proj (str or list): Projection type ('cyl', 'OrthoN', 'OrthoS', etc.).

        mode (str): Mode parameter description.

        Points (str): Points parameter description.

        id_stn (str): id_stn parameter description.

        channel (str): Channel parameter description.

        n_cpu (int): Number of CPUs to use.
   
       Returns:
       
         None
        """
        for family in families:
              pikobs.delete_create_folder(pathwork, family)
          
        data_list = create_data_list(datestart,
                                       dateend, 
                                       families, 
                                       files_in,
                                       names_in,
                                       pathwork,
                                       boxsizex,
                                       boxsizey, 
                                       fonctions, 
                                       flag_criteria, 
                                       regions,
                                       varnos,
                                       intervales)
                                       
       # exit()                             
        import time
        import dask
        t0 = time.time()
       # n_cpu=1
        if n_cpu==1:
          print (f'in Serie files: {len(data_list)} used in calculating statistics for {names_in}')
          for  data_ in data_list:  
               create_and_populate_moyenne_table(data_['family'], 
                                                 data_['db_new'], 
                                                 data_['filein'],
                                                 data_['region'],
                                                 data_['flag_criteria'],
                                                 data_['fonction'],
                                                 data_['boxsizex'],
                                                 data_['boxsizey'],
                                                 data_['varnos'],
                                                 channel,
                                                 id_stn,
                                                 data_['interval'])
               
       
       
       
       
        else:
           print (f'in Paralle number of files: {len(data_list)} used in calculating statistics for {len(data_list)}  {names_in} ')
           with dask.distributed.Client(processes=True, threads_per_worker=1, 
                                              n_workers=n_cpu, 
                                              silence_logs=40) as client:
               delayed_funcs = [dask.delayed(create_and_populate_moyenne_table)(data_['family'], 
                                                 data_['db_new'], 
                                                 data_['filein'],
                                                 data_['region'],
                                                 data_['flag_criteria'],
                                                 data_['function'],
                                                 data_['boxsizex'],
                                                 data_['boxsizey'],
                                                 data_['varnos'],
                                                 channel,
                                                 id_stn,
                                                 data_['interval'])for data_ in data_list]
              # print ('close0')
               results = dask.compute(*delayed_funcs)
               
               client.close()

        tn= time.time()
        print ('Total time for statistics:',tn-t0 )  
        time.sleep(5)

        data_list_plot = create_data_list_plot(datestart,
                                             dateend, 
                                             families, 
                                             names_in,
                                             pathwork,
                                             boxsizex,
                                             boxsizey, 
                                             flag_criteria, 
                                             regions,
                                             id_stn,
                                             channel,
                                             projs)

        t0 = time.time()
        if n_cpu==1:  
         print (f'in Serie plots = {len(data_list_plot)}')
         for  data_ in data_list_plot:  
           pikobs.histogram_plot(mode, 
                               data_['region'],
                               data_['family'], 
                               data_['id_stn'], 
                               datestart,
                               dateend, 
                               pathwork,
                               flag_criteria, 
                               data_['vcoord'],
                               data_['file_in'],
                               names_in, 
                               data_['varno'])
        else:
         print (f"in Paralle plots = {len(data_list_plot)}")
         time.sleep(4)
         with dask.distributed.Client(processes=True, threads_per_worker=1, 
                                          n_workers=n_cpu, 
                                          silence_logs=40) as client:
           delayed_funcs = [dask.delayed(pikobs.histogram_plot)( 
                                                              data_['region'],
                                                              data_['family'], 
                                                              data_['id_stn'],
                                                              datestart,
                                                              dateend, 
                                                              pathwork,
                                                              flag_criteria, 
                                                              data_['vcoord'],
                                                              data_['files_in'],
                                                              names_in,
                                                              data_['varno']
                                                            ) for data_ in data_list_plot]
   
           results = dask.compute(*delayed_funcs)
           client.close()
        print ('Total time:',time.time() - t0 )  
        print (f'check: {pathwork}')
    
import argparse
import re
import argparse
import re

def parse_intervals(text):
    """Parses a string of intervals formatted as '[(,),(a,b)]' into a list of tuples."""

    # Expresión regular corregida para aceptar paréntesis vacíos y números
    pattern = r'\(\s*(\d*)\s*,\s*(\d*)\s*\)'  
    matches = re.findall(pattern, text)


    result = []
    for a, b in matches:
        val_a = int(a) if a.isdigit() else None
        val_b = int(b) if b.isdigit() else None
        result.append((val_a, val_b))

    return result

def arg_call():

    import argparse
    import sys
    parser = argparse.ArgumentParser()
    parser.add_argument('--path_control_files', default='undefined', type=str, help="Directory where input sqlite files are located")
    parser.add_argument('--control_name', default='undefined', type=str, help="Directory where input sqlite files are located")
    parser.add_argument('--path_experience_files', default='undefined', type=str, help="Directory where input sqlite files are located")
    parser.add_argument('--experience_name', default='undefined', type=str, help="Directory where input sqlite files are located")
  

    
    parser.add_argument('--pathwork', default='undefined', type=str, help="Working directory")
    parser.add_argument('--datestart', default='undefined', type=str, help="Start date")
    parser.add_argument('--dateend', default='undefined', type=str, help="End date")
    parser.add_argument('--region', nargs="+", default='undefined', type=str, help="Region")
    parser.add_argument('--family', nargs="+", default='undefined', type=str, help="Family")
    parser.add_argument('--flags_criteria', default='undefined', type=str, help="Flags criteria")
    parser.add_argument('--fonction', nargs="+", default='undefined', type=str, help="Function") 
    parser.add_argument('--varnos', nargs="+", default='undefined', type=str, help="Function")
    parser.add_argument('--boxsizex', default=2, type=int, help="Box size in X direction")
    parser.add_argument('--boxsizey', default=2, type=int, help="Box size in Y direction")
    parser.add_argument('--projection', nargs="+", default='cyl', type=str, help="Projection type (cyl, OrthoN, OrthoS, robinson, Europe, Canada, AmeriqueNord, Npolar, Spolar, reg)")
    parser.add_argument('--mode', default='SIGMA', type=str, help="Mode")
    parser.add_argument('--Points', default='OFF', type=str, help="Points")
    parser.add_argument('--id_stn', default='one_per_plot', type=str, help="id_stn") 
    parser.add_argument('--channel', default='one_per_plot', type=str, help="channel")
    parser.add_argument('--n_cpus', default=1, type=int, help="Number of CPUs")
    parser.add_argument(
    "--layer",
    type=str,
    nargs="?",
    default="[(,)]",  # Valor por defecto
    help="Lista de intervalos, ejemplo: '[(,),(700,900)]'"
)
    
    args = parser.parse_args()
    for arg in vars(args):
       print (f'--{arg} {getattr(args, arg)}')
    # Check if each argument is 'undefined'
    if args.path_control_files == 'undefined':
        files_in = [args.path_experience_files]
        names_in = [args.experience_name]
    else:    
        if args.path_experience_files == 'undefined':
            raise ValueError('You must specify --path_experience_files')
        if args.experience_name == 'undefined':
            raise ValueError('You must specify --experience_name')
        else:

            files_in = [args.path_control_files, args.path_experience_files]
            names_in = [args.control_name, args.experience_name] 
    intervals = parse_intervals(args.layer)
    args = parser.parse_args()


    if args.varnos == 'undefined':
        args.varnos = []
    if args.pathwork == 'undefined':
        raise ValueError('You must specify --pathwork')
    if args.datestart == 'undefined':
        raise ValueError('You must specify --datestart')
    if args.dateend == 'undefined':
        raise ValueError('You must specify --dateend')
    if args.region == 'undefined':
        raise ValueError('You must specify --region')
    if args.family == 'undefined':
        raise ValueError('You must specify --family')
    if args.flags_criteria == 'undefined':
        raise ValueError('You must specify --flags_criteria')


    # Comment
    # Proj='cyl' // Proj=='OrthoN'// Proj=='OrthoS'// Proj=='robinson' // Proj=='Europe' // Proj=='Canada' // Proj=='AmeriqueNord' // Proj=='Npolar' //  Proj=='Spolar' // Proj == 'reg'
  

    #print("in")
    # Call your function with the arguments
    sys.exit(make_histogram(files_in,
                          names_in,    
                          args.pathwork,
                          args.datestart,
                          args.dateend,
                          args.region,
                          args.family,
                          args.flags_criteria,
                          args.fonction,
                          args.varnos,
                          args.boxsizex,
                          args.boxsizey,
                          args.projection,
                          args.mode,
                          args.Points,
                          args.id_stn,
                          args.channel,
                          args.n_cpus,
                          intervals))
