"""
@package pmsco.igor
data exchange with wavemetrics igor pro.

this module provides functions for loading/saving pmsco data in igor pro.

@author Matthias Muntwiler

@copyright (c) 2019-23 by Paul Scherrer Institut @n
Licensed under the Apache License, Version 2.0 (the "License"); @n
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at
  http://www.apache.org/licenses/LICENSE-2.0
"""

import numpy as np


def _escape_igor_string(s):
    s = s.replace('\\', '\\\\')
    s = s.replace('"', '\\"')
    return s


def namefix_double(name):
    """
    fix 1-character wave name by doubling

    replaces length-1 string by a doubled version.

    @param name: (str) proposed wave name

    @return: corrected name
    """
    return name*2 if len(name) == 1 else name


def namefix_etpais(name):
    """
    fix 1-character wave name according to ETPAIS scheme

    replaces 'e' by 'en' etc.

    @param name: (str) proposed wave name

    @return: corrected name
    """
    name_map = {'e': 'en', 't': 'th', 'p': 'ph', 'i': 'in', 'm': 'mo', 's': 'si'}
    try:
        return name_map[name]
    except KeyError:
        return name


class IgorExport(object):
    """
    class exports pmsco data to an Igor text (ITX) file.

    usage:
    1) create an object instance.
    2) set @ref data.
    3) set optional attributes: @ref prefix and @ref namefix.
    4) call @ref export.
    """

    def __init__(self):
        super(IgorExport, self).__init__()
        self.data = None
        self.prefix = ""
        self.namefix = namefix_double

    def set_data(self, data):
        """
        set the data array to export.

        this must (currently) be a one-dimensional structured array.
        the column names will become wave names.

        @param data: numpy.ndarray
        @return:
        """
        self.data = data

    def export(self, filename):
        """
        write to igor file.
        """
        with open(filename, 'wt', encoding="utf8") as f:
            self._write_header(f)
            self._write_data(f)

    def _fix_name(self, name):
        """
        fix a wave name.

        this function first applies @ref namefix and @ref prefix to the proposed wave name.

        @param name: (str) proposed wave name

        @return: corrected name
        """
        if self.namefix is not None:
            name = self.namefix(name)
        return self.prefix + name

    def _write_header(self, f):
        """
        write the header of the igor text file

        @param f: open file or stream

        @return: None
        """
        f.write('IGOR' + '\n')
        f.write('X // pmsco data export\n')

    def _write_data(self, f):
        """
        write a data section to the igor text file.

        @param f: open file or stream

        @return: None
        """
        assert isinstance(self.data, np.ndarray)
        assert len(self.data.shape) == 1
        assert len(self.data.dtype.names[0]) >= 1

        arr = self.data
        shape = ",".join(map(str, arr.shape))
        names = (self._fix_name(name) for name in arr.dtype.names)
        names = ", ".join(names)

        f.write('Waves/O/D/N=({shape}) {names}\n'.format(shape=shape, names=names))
        f.write('BEGIN\n')
        np.savetxt(f, arr, fmt='%g')
        f.write('END\n')
