# Copyright (C) 2018 Paul King

# Licensed under the Apache License, Version 2.0 (the "License");
# 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

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from collections import namedtuple

from pymedphys._imports import numpy as np

# from scipy.interpolate import interp1d


def read_prs(file_name):
    """
    Read native Profiler data file and return dose profiles.

    Parameters
    ----------
    file_name : string
        | file name of Profiler file including path

    Returns
    -------
    Profiler : named tuple
        | Profiler.cax = float dose at central axis
        | Profiler.x = list of (x, dose) tuples
        | Profiler.y = list of (y, dose) tuples
    """

    Profiler = namedtuple("Profiler", ["cax", "x", "y"])

    with open(file_name) as profiler_file:
        for row in profiler_file.readlines():
            contents = row
            if contents[:11] == "Calibration" and "File" not in contents:
                calibs = np.array(contents.split())[1:].astype(float)
            elif contents[:5] == "Data:":
                counts = np.array(contents.split()[5:145]).astype(float)
            elif contents[:15] == "Dose Per Count:":
                dose_per_count = float(contents.split()[-1])
        assert (len(calibs)) == (len(counts)) == 140
        assert dose_per_count > 0.0
    dose = counts * dose_per_count * calibs

    y_vals = [-16.4 + 0.4 * i for i in range(83)]
    x_vals = [-11.2 + 0.4 * i for i in range(57)]

    x_prof = list(zip(y_vals, dose[:57]))
    y_prof = list(zip(x_vals, dose[57:]))

    assert np.allclose(y_prof[41][1], x_prof[28][1])
    cax_dose = y_prof[41][1]

    return Profiler(cax_dose, x_prof, y_prof)


# All tests passed incorrect x and y values and got the write_prs
# function to silently, implicitly interpolate.

# Removed silent interpolation, then all tests failed. Therefore until
# this function is improved it is removed.

# def write_prs(x_prof, y_prof,file_name=None,
#               version=7,
#               meas_date='01/01/1970', meas_time='00:00:01',
#               descrip='', instit='', file_cal="NONE", collector='Profiler2',
#               coll_sn='0000000', coll_rev='C',
#               f_ware_ver='0.0.0', s_ware_v='0.0.0.0',
#               depth='1.0', nom_gain='1', orient='Sagittal', ssd='100',
#               bm_mode='Pulsed', tray='No', align='None', interval='50',
#               room='', mach_type='', mach_mod='',mach_num='',
#               bm_modal='Photon', bm_energy='0', jaws=('5','5','5','5'),
#               wdg_type='None', wdg_ang='0', rate='0', dose='0',
#               gantry='180', collimator='180', bkg_used='true',
#               pulse_mode='true', alz_panels='0000000', cal_sn='0000000',
#               cal_rev='A', temp='-100', dose_cal = '0.001', d_at_cal='100.0',
#               abs_cal='false', energy_cal='0', cal_date='01/01/1970',
#               cal_time='00:00:01', cal_cmnts='', m_frame='false',
#               updates='0', pulses='0', time='0.0',
#               detectors=('83', '57', '0', '4'), spacing='0.4',
#               concat='false'):

#     """
#     Write dose profiles to a file in the native Profiler data format.

#     Arguments:
#         x_prof -- x profile, i.e. [(distance, dose), ...]
#         y_prof -- y profile, i.e. [(distance, dose), ...]

#     Keyword Argument [generally needed]:
#         file_name -- output long file name, None -> return string only

#     Keyword Arguments [not generally needed]:
#         ** defaults to reasonable values
#         ** many of these values do not affect converted profiles
#         ---------
#         meas_date -- string, e.g. '11/10/2018'
#         meas_time -- string, e.g. '16:56:28'
#         descrip   -- string description
#         instit    -- string institution
#         file_cal  -- long path to calibraiton file, N/A for converted
#         collector -- string collector model, i.e. Profiler2
#         coll_sn   -- string collector serial number, e.g. '1234567'
#         coll_rev  -- string collector revision letter, e.g. 'C'
#         f_ware_ver-- string firmware version, e.g. '1.2.1'
#         s_ware_v  -- string software version, e.g. '1.1.0.0'
#         depth     -- string measurement depth in cm
#         nom_gain  -- string nominal gain, e.g. '1',
#         orient    -- string orientation, e.g. 'Sagittal',
#         ssd       -- string SSD in cm, e.g. '100'
#         bm_mode   -- string beam mode, e.g. 'Pulsed'
#         tray      -- string e.g. 'No', 'Yes'
#         align     -- string, e.g. 'None', 'Light Field', 'Cross Hair'
#         interval  -- string collection interval, e.g. 50, must be >0
#         room      -- string room description
#         mach_type -- string machine type description
#         mach_mod  -- string machine model
#         mach_num  -- string machine serial number
#         bm_modal  -- string beam modality, e.g.'Photon', 'Electron', 'Cobalt'
#         bm_energy -- string beam nominal in MV or MeV, e.g. '6'
#         jaws      -- tuple of string jaw positions in cm: (l, r, t, b)
#         wdg_type  -- string type, e.g. 'None', 'Static', 'Dynamic', 'Virtual'
#         wdg_ang   -- string angle, e.g. '0',
#         rate      -- string dose rate, e.g. '300'
#         dose      -- string total dose, e.g. '100'
#         gantry    -- string gantry angle in deg, e.g. '180'
#         collimator-- string collimator angle in deg, e.g. '180'
#         bkg_used  -- string background used, e.g. 'true'
#         pulse_mode-- string pulse mode, e.g.'true'
#         alz_panels-- string analyze panels, e.g. ='1015679')
#         cal_sn    -- string calibration serial num, e.g. '1234567'
#         cal_rev   -- string calibration revision letter, e.g. 'C',
#         temp      -- string temparature, internal scale, e.g. '-98.96726775'
#         dose_cal  -- string dose per count, e.g. '0.001' for 1000 cts per cGy
#         d_at_cal  -- string dose used for absolute calibration, e.g. "75.40153"
#         abs_cal   -- string absolute calibration, e.g. 'false', 'true'
#         energy_cal-- string energy of calibration, e.g. '4'
#         cal_date  -- string, e.g. '11/10/2018'
#         cal_time  -- string, e.g. '16:56:28'
#         cal_cmnts -- string calibration comments
#         m_frame   -- string mult-frame, e.g.'false', 'true
#         updates   -- string number of updates, e.g.'25',
#         pulses    -- string number of pulses, e.g.'3939'
#         time      -- string total measurement time in sec, e.g. '12.5'
#         detectors -- tuple of string, Profiler2 -> ('83', '57', '0', '4')
#         spacing   -- string detector spacing, e.g.'0.4'
#         concat    -- string concatenated measuremets, e.g. 'false'


#     Returns:
#         The contents of the file as a list of strings.
#     """

#     # EXTEND PROFILE TAILS, TO ENSURE LONGER THAN DEVICE
#     x_prof = [(-1000, 0)] + x_prof + [(1000, 0)]
#     y_prof = [(-1000, 0)] + y_prof + [(1000, 0)]

#     # X,Y DETECTOR POSITIONS FOR DEVICE
#     x_vals = [-11.2 + 0.4*i for i in range(57)]
#     y_vals = [-16.4 + 0.4*i for i in range(83)]

#     # X,Y COORDINATES CORRECT, DO NOT INTERPOLATE
#     if [i[0] for i in x_prof] == x_vals and [i[0] for i in y_prof] == y_vals:
#         counts = ['Data:', '0', '0', '0', '0'] + \
#             [str(int(1000*i[1])) for i in x_prof + y_prof] + \
#             ['0', '0', '0', '0\n']

#     else:
#         raise ValueError("invalid x and y coords provided")


#     prs_file = ['Version:\t {}\n'.format(7),
#                 'Filename:\t {} \n'.format('-'),
#                 'Date:\t {}\t Time:\t{}\n'.format(meas_date, meas_time),
#                 'Description:\t{}\n'.format(descrip),
#                 'Institution:\t{}\n'.format(instit),
#                 'Calibration File:\t{}\n'.format(file_cal),
#                 '\tProfiler Setup\n', '\n',
#                 'Collector Model:\t{}\n'.format(collector),
#                 'Collector Serial:\t{} Revision:\t{}\n'.format(
#                     coll_sn, coll_rev),
#                 'Firmware Version:\t{}\n'.format(f_ware_ver),
#                 'Software Version:\t{}\n'.format(s_ware_v),
#                 'Buildup:\t{}\tcm\tWaterEquiv\n'.format(depth),
#                 'Nominal Gain\t{}\n'.format(nom_gain),
#                 'Orientation:\t{}\n'.format(orient),
#                 'SSD:\t{}\tcm\n'.format(ssd),
#                 'Beam Mode:\t{}\n'.format(bm_mode),
#                 'Tray Mount:\t{}\n'.format(tray),
#                 'Alignment:\t{}\n'.format(align),
#                 'Collection Interval:\t{}\n'.format(interval),
#                 '\n',
#                 '\tMachine Data\n',
#                 'Room:\t{}\n'.format(room),
#                 'Machine Type:\t{}\n'.format(mach_type),
#                 'Machine Model:\t{}\n'.format(mach_mod),
#                 'Machine Serial Number:\t{}\n'.format(mach_num),
#                 'Beam Type:\t{}\tEnergy:\t{} MeV\n'.format(
#                     bm_modal, bm_energy),
#                 'Collimator:\tLeft: {} Right: {} Top: {} Bottom: {} cm\n'.format(
#                    *jaws),
#                 'Wedge:\t{}\tat\t{}\n'.format(wdg_type, wdg_ang),
#                 'Rate:\t{}\tmu/Min\tDose:\t{}\n'.format(rate, dose),
#                 'Gantry Angle:\t{} deg\tCollimator Angle:\t{} deg\n'.format(
#                     gantry, collimator),
#                 '\n',
#                 '\tData Flags\n',
#                 'Background Used:\t{}\n'.format(bkg_used),
#                 'Pulse Mode:\t{}\n'.format(pulse_mode),
#                 'Analyze Panels:\t{}\n'.format(alz_panels),
#                 '\n',
#                 '\tHardware Data\n',
#                 'Cal-Serial Number:\t{}\n'.format(cal_sn),
#                 'Cal-Revision:\t{}\n'.format(cal_rev),
#                 'Temperature:\t{}\n'.format(temp),
#                 'Dose Calibration\n',
#                 'Dose Per Count:\t{}\n'.format(dose_cal),
#                 'Dose:\t{}\n'.format(d_at_cal),
#                 'Absolute Calibration:\t{}\n'.format(abs_cal),
#                 'Energy:\t{} MV\n'.format(energy_cal),
#                 'TimeStamp:\t{} {}\n'.format(cal_date, cal_time),
#                 'Comments:\t{}\n'.format(cal_cmnts),
#                 'Gain Ratios for Amp0:\t\t{}\t{}\t{}\t{}\n'.format(1, 2, 4, 8),
#                 'Gain Ratios for Amp1:\t\t{}\t{}\t{}\t{}\n'.format(1, 2, 4, 8),
#                 'Gain Ratios for Amp2:\t\t{}\t{}\t{}\t{}\n'.format(1, 2, 4, 8),
#                 'Gain Ratios for Amp3:\t\t{}\t{}\t{}\t{}\n'.format(1, 2, 4, 8),
#                 '\n',
#                 'Multi Frame:\t{}\n'.format(m_frame),
#                 '# updates:\t{}\n'.format(updates),
#                 'Total Pulses:\t{}\n'.format(pulses),
#                 'Total Time:\t{}\n'.format(0.0),
#                 'Detectors:\t{}\t{}\t{}\t{}\n'.format(*detectors),
#                 'Detector Spacing:\t{}\n'.format(spacing),
#                 'Concatenation:\t{}\n'.format(concat),
#                 '\t'.join(['TYPE',
#                            'UPDATE#',
#                            'TIMETIC',
#                            'PULSES',
#                            'ERRORS'] +
#                           ['X'+str(i) for i in range(1, 58)] +
#                           ['Y'+str(i) for i in range(1, 84)] +
#                           ['Z0', 'Z1', 'Z2', 'Z3\n']),
#                 '\t'.join(['BIAS1', '', '0', '',
#                            ''] + ['0.0']*143 + ['0.0\n']),
#                 '\t'.join(['Calibration', '', '', '', ''] +
#                           ['1.0']*139 + ['1.0\n']),
#                 '\t'.join(counts)]

#     with open(file_name, 'w') as outfile:
#         for line in prs_file:
#             outfile.write(line)
#     return prs_file
