#!/usr/bin/python3

'''
qtplasmac-plasmac2qt.py

This file is used to convert settings in the .cfg files from a PlasmaC
configuration to the .prefs file for a QtPlasmaC configuration.

Copyright (C) 2020, 2021 Phillip A Carter
Copyright (C) 2020, 2021  Gregory D Carl

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
'''

import os
import sys
import time
from shutil import copy as COPY
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *

class Converter(QMainWindow, object):

# INITIALISATION
    def __init__(self, parent=None):
        super(Converter, self).__init__(parent)
        self.appPath = os.path.realpath(os.path.dirname(sys.argv[0]))
        if len(sys.argv) > 1:
            if os.path.isfile(sys.argv[1]):
                self.mode = 'auto'
                self.iniIn = sys.argv[1]
            else:
                print('{} is not a valid file.'.format(sys.argv[1]))
                sys.exit(0)
        else:
            self.mode = ''
            self.iniIn = ''
        if 'usr' in self.appPath:
            self.simPath = '/usr/share/doc/linuxcnc/examples/sample-configs/sim/qtplasmac'
        else:
            self.simPath = self.appPath.replace('bin', 'configs/sim/qtplasmac')
        self.setFixedWidth(600)
        self.setFixedHeight(400)
        wid = QWidget(self)
        qtRectangle = self.frameGeometry()
        centerPoint = QDesktopWidget().availableGeometry().center()
        qtRectangle.moveCenter(centerPoint)
        self.move(qtRectangle.topLeft())
        self.setCentralWidget(wid)
        layout = QHBoxLayout()
        wid.setLayout(layout)
        iconPath = 'share/icons/hicolor/scalable/apps/linuxcnc_alt/linuxcncicon_plasma.svg'
        appPath = os.path.realpath(os.path.dirname(sys.argv[0]))
        iconBase = '/usr' if appPath == '/usr/bin' else appPath.replace('/bin', '/debian/extras/usr')
        self.setWindowIcon(QIcon(os.path.join(iconBase, iconPath)))
        self.setWindowTitle('PlasmaC2Qt')
        vBox = QVBoxLayout()
        if self.mode == 'auto':
            heading  = 'Plasmac is not available in LinuxCNC V2.9 and later\n\n'
        else:
            heading = ''
        heading += 'Convert Existing PlasmaC Configuration To A New QtPlasmaC Configuration\n'
        headerLabel = QLabel(heading)
        headerLabel.setAlignment(Qt.AlignCenter)
        vBox.addWidget(headerLabel)
        vSpace01 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        vBox.addItem(vSpace01)
        fromLabel = QLabel('INI FILE IN EXISTING PLASMAC CONFIG:')
        fromLabel.setAlignment(Qt.AlignBottom)
        vBox.addWidget(fromLabel)
        fromFileHBox = QHBoxLayout()
        self.fromFile = QLineEdit()
        self.fromFile.setEnabled(False)
        if self.mode:
            self.fromFile.setText(self.iniIn)
        else:
            fromFileButton = QPushButton('SELECT')
            fromFileHBox.addWidget(fromFileButton)
        fromFileHBox.addWidget(self.fromFile)
        vBox.addLayout(fromFileHBox)
        vSpace02 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        vBox.addItem(vSpace02)
        aspectLabel = QLabel('MONITOR ASPECT RATIO:')
        vBox.addWidget(aspectLabel)
        aspectHBox = QHBoxLayout()
        self.aspectGroup = QButtonGroup()
        self.aspect0 = QRadioButton('16:9')
        self.aspect0.setFixedHeight(25)
        self.aspect0.setChecked(True)
        aspectHBox.addWidget(self.aspect0)
        self.aspectGroup.addButton(self.aspect0, 0)
        self.aspect1 = QRadioButton('9:16')
        aspectHBox.addWidget(self.aspect1)
        self.aspectGroup.addButton(self.aspect1, 1)
        self.aspect2 = QRadioButton('4:3')
        aspectHBox.addWidget(self.aspect2)
        self.aspectGroup.addButton(self.aspect2, 2)
        self.aspectGroup.buttonClicked.connect(self.aspect_group_clicked)
        vBox.addLayout(aspectHBox)
        vSpace03 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        vBox.addItem(vSpace03)
        self.estopLabel = QLabel('ESTOP IS AN INDICATOR ONLY')
        vBox.addWidget(self.estopLabel)
        estopHBox = QHBoxLayout()
        self.estopGroup = QButtonGroup()
        self.estop0 = QRadioButton('ESTOP: 0')
        self.estop0.setFixedHeight(25)
        self.estop0.setChecked(True)
        estopHBox.addWidget(self.estop0)
        self.estopGroup.addButton(self.estop0, 0)
        self.estop1 = QRadioButton('ESTOP: 1')
        estopHBox.addWidget(self.estop1)
        self.estopGroup.addButton(self.estop1, 1)
        self.estop2 = QRadioButton('ESTOP: 2')
        estopHBox.addWidget(self.estop2)
        self.estopGroup.addButton(self.estop2, 2)
        self.estopGroup.buttonClicked.connect(self.estop_group_clicked)
        vBox.addLayout(estopHBox)
        vSpace3 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        vBox.addItem(vSpace3)
        laserOnLabel = QLabel('OPTIONAL:\nLaser On HAL pin: (bit output)')
        vBox.addWidget(laserOnLabel)
        self.laserOnPin = QLineEdit()
        vBox.addWidget(self.laserOnPin)
        vSpace04 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
        vBox.addItem(vSpace04)
        buttonHBox = QHBoxLayout()
        convert = QPushButton('CONVERT')
        buttonHBox.addWidget(convert)
        cancel = QPushButton('EXIT')
        buttonHBox.addWidget(cancel)
        vBox.addLayout(buttonHBox)
        layout.addLayout(vBox)
        self.setStyleSheet( \
            'QWidget {color: #ffee06; background: #16160e} \
             QLabel {height: 20} \
             QPushButton {border: 1 solid #ffee06; border-radius: 4; height: 24; width: 80; max-width: 90} \
             QFileDialog QPushButton {border: 1 solid #ffee06; border-radius: 4; height: 30; margin: 6} \
             QPushButton:pressed {color: #16160e; background: #ffee06} \
             QLineEdit {border: 1 solid #ffee06; border-radius: 4; height: 24; padding-left: 8} \
             QFileDialog QLineEdit {border: 1 solid #ffee06; border-radius: 4; height: 30} \
             QTableView::item:selected:active {color: #16160e; background-color: #ffee06} \
             QTableView::item:selected:!active {color: #16160e; background-color: #ffee06} \
             QHeaderView::section {color: #ffee06; background-color: #36362e; border: 1 solid #ffee06; border-radius: 4; margin: 2} \
             QComboBox {color: #ffee06; background-color: #16160e; border: 1 solid #ffee06; border-radius: 4; height: 30} \
             QComboBox::drop-down {width: 0} \
             QComboBox QListView {border: 4p solid #ffee06; border-radius: 0} \
             QComboBox QAbstractItemView {border: 2px solid #ffee06; border-radius: 4} \
             QScrollBar:horizontal {background: #36362e; border: 0; border-radius: 4; margin: 0; height: 20} \
             QScrollBar::handle:horizontal {background: #ffee06; border: 2 solid #ffee06; border-radius: 4; margin: 2; width: 40} \
             QScrollBar::add-line:horizontal {width: 0} \
             QScrollBar::sub-line:horizontal {width: 0} \
             QScrollBar:vertical {background: #36362e; border: 0; border-radius: 4; margin: 0; width: 20} \
             QScrollBar::handle:vertical {background: #ffee06; border: 2 solid #ffee06; border-radius: 4; margin: 2; height: 40} \
             QScrollBar::add-line:vertical {height: 0} \
             QScrollBar::sub-line:vertical {height: 0} \
             QRadioButton::indicator {border: 1px solid #ffee06; border-radius: 4; height: 20; width: 20} \
             QRadioButton::indicator:checked {background: #ffee06} \
            ')
        convert.pressed.connect(self.convert_pressed)
        cancel.pressed.connect(self.close_app)
        if not self.mode:
            fromFileButton.pressed.connect(self.from_pressed)
        if os.path.exists('{}/linuxcnc/configs'.format(os.path.expanduser('~'))):
            self.DIR = '{}/linuxcnc/configs'.format(os.path.expanduser('~'))
        elif os.path.exists('{}/linuxcnc'.format(os.path.expanduser('~'))):
            self.DIR = '{}/linuxcnc'.format(os.path.expanduser('~'))
        else:
            self.DIR = '{}'.format(os.path.expanduser('~'))
        self.display = 'DISPLAY                 = qtvcp qtplasmac\n'
        self.estop = 'Estop type = 0'

# POPUP INFO DIALOG
    def dialog_ok(self, title, text):
        msgBox = QMessageBox()
        msgBox.setIcon(QMessageBox.Information)
        msgBox.setWindowTitle('{}'.format(title))
        msgBox.setText('{}'.format(text))
        msgBox.setStandardButtons(QMessageBox.Ok)
        buttonK = msgBox.button(QMessageBox.Ok)
        buttonK.setIcon(QIcon())
        buttonK.setText('OK')
        msgBox.setStyleSheet('QWidget {color: #ffee06; background: #16160e; font: 12pt DejaVuSans} \
                              QPushButton {border: 1px solid #ffee06; border-radius: 4; height: 20} \
                             ')
        msgBox.setBaseSize(QSize(800, 800))
        ret = msgBox.exec_()
        return ret

# SELECT PLASMAC INI FILE
    def from_pressed(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        name, _ = QFileDialog.getOpenFileName(
                    parent=self,
                    caption=self.tr("Select an INI file"),
                    filter=self.tr('INI files (*.ini);;INI files (*.[iI][nN][iI])'),
                    directory=self.DIR,
                    options=options
                    )
        if name and os.path.isfile(name):
            self.fromFile.setText(name)
        else:
            self.fromFile.setText('')
        self.iniIn = self.fromFile.text()

# ASPECT CHANGED
    def aspect_group_clicked(self, button):
        if self.aspectGroup.id(button) == 0:
            self.display = 'DISPLAY                 = qtvcp qtplasmac\n'
        elif self.aspectGroup.id(button) == 1:
            self.display = 'DISPLAY                 = qtvcp qtplasmac_9x16\n'
        elif self.aspectGroup.id(button) == 2:
            self.display = 'DISPLAY                 = qtvcp qtplasmac_4x3\n'

# ESTOP CHANGED
    def estop_group_clicked(self, button):
        if self.estopGroup.id(button) == 0:
            self.estopLabel.setText('ESTOP IS AN INDICATOR ONLY')
            self.estop = 'Estop type = 0'
        elif self.estopGroup.id(button) == 1:
            self.estopLabel.setText('ESTOP IS HIDDEN')
            self.estop = 'Estop type = 1'
        elif self.estopGroup.id(button) == 2:
            self.estopLabel.setText('ESTOP IS A BUTTON')
            self.estop = 'Estop type = 2'

# CLOSE PROGRAM
    def close_app(self):
        sys.exit(2)

# CONVERT
    def convert_pressed(self):
    # CHECK IF INI FILE NAME EXISTS
        if not self.iniIn:
            return
    # CHECK IF FULL PATH EXISTS
        if not os.path.dirname(self.iniIn):
            msg  = 'Missing path to a PlasmaC configuration\n'
            self.dialog_ok('Path Error', msg)
            self.fromFile.setFocus()
            return
    # CHECK IF VALID PLASMAC CONFIG
        if not os.path.exists('{}/plasmac'.format(os.path.dirname(self.iniIn))):
            msg  = '{}\n'.format(self.iniIn)
            msg += '\n is not a PlasmaC configuration\n'
            self.dialog_ok('Config Error', msg)
            self.fromFile.setFocus()
            return
    # CHECK IF SIM CONFIG
        simConfig = False
        with open(self.iniIn, 'r') as inFile:
            for line in inFile:
                if 'plasmac_test.py' in line and not line.startswith('#'):
                    simConfig = True
                    break
    # SET FILENAMES AND PATHS
        fName = os.path.basename(self.iniIn)
        newDir = os.path.dirname(self.iniIn)
        i = 1
        while True:
            oldDir = '{}.bkp{}'.format(os.path.dirname(self.iniIn), i)
            if not os.path.exists(oldDir):
                break
            i += 1
        newIniFile = os.path.join(newDir, fName)
        oldIniFile = os.path.join(oldDir, fName)
    # CREATE NEW DIRECTORY AND BACKUPS DIRECTORY
        try:
            os.rename(newDir, oldDir)
            os.makedirs('{}/backups'.format(newDir))
        except:
            msg  = 'Could not create directory\n'.format(newDir)
            self.dialog_ok('Directory Error', msg)
            return
    # GET THE MACHINE NAME
        with open(oldIniFile) as inFile:
            while(1):
                line = inFile.readline()
                if not line:
                    print('cannot find [EMC] section in INI file')
                    return
                if line.startswith('[EMC]'):
                    break
            while(1):
                line = inFile.readline()
                if not line:
                    print('cannot find MACHINE variable in INI file')
                    return
                if line.startswith('MACHINE'):
                    machineName = line.split('=')[1].strip().lower()
                    break
    # COPY ORIGINAL BASE MACHINE FILES IF EXISTING
        try:
            for filename in os.listdir('{}/backups'.format(oldDir)):
                if filename.startswith('_original'):
                    COPY('{}/backups/{}'.format(oldDir, filename), '{}/backups/{}'.format(newDir, filename))
        except:
            pass
    # COPY HAL FILES
        halFiles = []
        oldPostguiFile = None
        newPostguiFile = None
        newConnectionsFile = None
        with open(oldIniFile, 'r') as inFile:
            while(1):
                line = inFile.readline()
                if line.startswith('[HAL]'):
                    break
                if not line:
                    msg  = 'Could not get [HAL] section of INI file\n'
                    msg += '\nConversion cannot continue'
                    self.dialog_ok('INI File Error', msg)
                    self.fromFile.setFocus()
                    return
            while(1):
                line = inFile.readline()
                if line.startswith('POSTGUI_HALFILE'):
                    oldPostguiFile = line.split('=')[1].strip()
                    newPostguiFile = 'custom_postgui.hal'
                    halFiles.append(oldPostguiFile)
                    COPY('{}/{}'.format(oldDir, oldPostguiFile), '{}/{}'.format(newDir, newPostguiFile))
                elif 'connections.hal' in line:
                    oldConnectionsFile = line.split('=')[1].strip()
                    newConnectionsFile = 'custom.hal'
                    halFiles.append(newConnectionsFile)
                    COPY('{}/{}'.format(oldDir, oldConnectionsFile), '{}/{}'.format(newDir, newConnectionsFile))
                    with open('{}/{}'.format(newDir, newConnectionsFile), 'w') as outConFile:
                        with open('{}/{}'.format(oldDir, oldConnectionsFile), 'r') as inConFile:
                            for line in inConFile:
                                if 'plasmac:torch-on' in line:
                                    outConFile.write(line)
                                    outConFile.write('\n#***** LASER ALIGNMENT CONNECTION *****\n')
                                    if self.laserOnPin.text():
                                        outConFile.write('net plasmac:laser-on => {}\n'.format(self.laserOnPin.text()))
                                    else:
                                        outConFile.write('# net plasmac:laser-on => {YOUR_LASER_ON_OUTPUT}\n\n')
                                else:
                                    outConFile.write(line)
                elif line.startswith('HALFILE'):
                    if 'plasmac.tcl' in line:
                        halFiles.append('plasmac.tcl')
                    else:
                        hFile = line.split('=')[1].strip()
                        with open('{}/{}'.format(oldDir, hFile), 'r') as inHal:
                            if simConfig and 'motor-pos-cmd' in inHal.read():
                                halFiles.append('machine.tcl')
                                COPY('{}/machine.tcl'.format(self.simPath), '{}/machine.tcl'.format(newDir))
                            else:
                                halFiles.append(hFile)
                                COPY('{}/{}'.format(oldDir, hFile), '{}/{}'.format(newDir, hFile))
                if not line or line.startswith('['):
                    break
    # COPY TOOL TABLE
        if os.path.exists('{}/tool.tbl'.format(oldDir)):
            COPY('{}/tool.tbl'.format(oldDir), '{}/tool.tbl'.format(newDir))
    # MAKE NEW PREFERENCES FILE
        self.prefParms = []
        self.read_ini_file(oldIniFile)
        if os.path.isfile(os.path.join(oldDir, machineName + '_config.cfg')):
            self.read_con_file(os.path.join(oldDir, machineName + '_config.cfg'))
        else:
            print('file not found, config parameters can not be converted.')
        if os.path.isfile(os.path.join(oldDir, machineName + '_run.cfg')):
            self.read_run_file(os.path.join(oldDir, machineName + '_run.cfg'))
        else:
            print('file not found, run parameters can not be converted.')
        if os.path.isfile(os.path.join(oldDir, machineName + '_wizards.cfg')):
            self.read_wiz_file(os.path.join(oldDir, machineName + '_wizards.cfg'))
        else:
            print('file not found, wizard parameters can not be converted.')
        if os.path.isfile(os.path.join(oldDir, 'plasmac_stats.var')):
            self.read_sta_file(os.path.join(oldDir, 'plasmac_stats.var'))
        else:
            print('file not found, statistics can not be converted.')
        if os.path.isfile(os.path.join(oldDir, machineName + '_material.cfg')):
            self.read_mat_file(os.path.join(oldDir, machineName + '_material.cfg'), newDir, machineName)
        else:
            print('file not found, materials can not be converted.')
        self.write_prefs_files(newDir, machineName)
    # MAKE NEW INI FILE
        section = ''
        with open(newIniFile, 'w') as outFile:
            with open(oldIniFile, 'r') as inFile:
                for line in inFile:
                # SET SECTION NAMES
                    if line.startswith('['):
                        section = ''
                    if line.startswith('[APPLICATIONS]'):
                        section = 'APPLICATIONS'
                    if line.startswith('[PLASMAC]'):
                        section = 'PLASMAC'
                    if line.startswith('[FILTER]'):
                        section = 'FILTER'
                    if line.startswith('[RS274NGC]'):
                        section = 'RS274NGC'
                    if line.startswith('[HAL]'):
                        section = 'HAL'
                    if line.startswith('[DISPLAY]'):
                        section = 'DISPLAY'
                    if line.startswith('[EMC]'):
                        section = 'EMC'
                # CONVERT SECTION PARAMETERS
                    if section == 'APPLICATIONS':
                        continue
                    if section == 'PLASMAC':
                        continue
                    elif section == 'FILTER':
                        if line.startswith('[FILTER]'):
                            outFile.write('\n{}'.format(line))
                            outFile.write('PROGRAM_EXTENSION       = .ngc,.nc,.tap GCode File (*.ngc, *.nc, *.tap)\n')
                            outFile.write('ngc                     = qtplasmac_gcode\n')
                            outFile.write('nc                      = qtplasmac_gcode\n')
                            outFile.write('tap                     = qtplasmac_gcode\n')
                        continue
                    elif section == 'RS274NGC':
                        if line.startswith('SUBROUTINE') or line.startswith('USER_M_PATH'):
                            if ':./plasmac' in line:
                                line = line.replace(':./plasmac', '')
                            if line.strip().endswith('./') or './:' in line:
                                pass
                            else:
                                line = './:{}'.format(line)
                        if line.startswith('RS274NGC_STARTUP_CODE') and ('metric' in line or 'imperial' in line):
                            units = 21 if 'metric' in line else 20
                            line = 'RS274NGC_STARTUP_CODE   = G{} G40 G49 G80 G90 G92.1 G94 G97 M52P1\n'.format(units)
                        if line.startswith('#') or line.replace(' ', '').strip() == 'FEATURES=12':
                            continue
                        if line.startswith('['):
                            outFile.write('\n')
                        if line.strip():
                            outFile.write(line)
                        continue
                    elif section == 'HAL':
                        if line.startswith('[HAL]'):
                            outFile.write('\n{}'.format(line))
                            outFile.write('TWOPASS                 = ON\n')
                            outFile.write('HALUI                   = halui\n')
                            for file in halFiles:
                                if '_connections' in file:
                                    outFile.write('HALFILE                 = custom.hal\n')
                                elif 'postg                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        