require("luamods/command")
require("luamods/layout")
require("luamods/cgi")
require("config/rsm_conf")
require("luamods/rsm_serials")

header = layout.getHeader()
footer = layout.getFooter()

userLevel = db.getPriv(layout.username) or 1

function log(m)
   command.ex([[logger -t webconfig ]]..[["]]..m..[["]])
end

if (userLevel == 1) then
    buttonControl = " disabled"
    inputControl = " readonly"
else
    buttonControl = ""
    inputControl = ""
end

serialConfig = command.ex([[cat ]]..rsm_conf.serialconfig_path) or ""

modbusConfig = command.ex([[cat ]]..rsm_conf.mdd_xml_path) or ""
templatesFiles = {}
if (modbusConfig ~= "") then
    modbusPath = modbusConfig:match([[<path%s+name=%"devices%"%s->(.-)</path>]]) or ""
    templatesPath = modbusConfig:match([[<path%s+name=%"templates%"%s->(.-)</path>]]) or ""
    if (templatesPath ~= "") then
        templatesFiles = command.getFilesInTable(templatesPath)
    end
end

if (cgi.post.deleteButton == "Delete Device") and (userLevel ~= 1) then
    file = cgi.post.file or ""
    file = file:gsub("[^%w%.]+","")
    command.ex(rsm_conf.mdd_down)
    command.ex([[rm ]]..modbusPath..[[/]]..file)
    command.ex(rsm_conf.mdd_up)
    label = cgi.post.label or "unknown"
    bus = cgi.post.bus or "unknown"
    -- Stop here
    content = [[
                    <div id="info">
                        <center><h1>Edit ModBus Device</h1></center>
                    </div>                  
                    <div id="info">
                        <center>
                            <h2><img src="images/ok.png"/> Device Deleted</h2>
                            Device with filename "]]..file..[[" has been removed.<br><br>
                            <a href="rsm_modbus_config.lua?bus=]]..bus..[[">Back to ModBus</a>
                        </center>
                    </div>
]]
    print(header..content..footer)
    os.exit()
end

if (cgi.post.saveButton == "Save and Apply") and (userLevel ~= 1) then
    newFile = cgi.post.file or ""
    newFile = newFile:gsub("[^%w%.]+","")
    if (newFile == "") then
        newSerial = rsm_serials.generateNewSerial()
        newFile = newSerial..".xml"
        createdNew = 1
    else
        createdNew = 0
        existingCfg = command.ex([[cat ]]..modbusPath..[[/]]..newFile)
        newSerial = existingCfg:match([[<serial>%s-(.-)%s-</serial>]])
        if (newSerial == nil) then
            -- Bail on error
            content = [[
                    <div id="info">
                        <center><h1>Edit ModBus Device</h1></center>
                    </div>                  
                    <div id="info">
                        <center>
                            <h2><img src="images/warning.png"/> Filename / serial mismatch</h2>
                            The serial number of the device does not match the one in the file.<br>
                            <a href="rsm_bus_config.lua">Back to Bus Configuration</a>
                        </center>
                    </div>
]]
            print(header..content..footer)
            os.exit()
        end
    end
    newLabel = cgi.post.label or "unknown"
    newTemplate = cgi.post.template or "unknown"
    newConfig = cgi.post.config or rsm_conf.serialconfig_path
    newPort = cgi.post.bus or "unknown"
    newOwner = "mdd"
    newSlave = cgi.post.slave or "unknown"
    newMuxport = cgi.post.muxport or "unknown"
    newMuxslave = cgi.post.muxslave or "unknown"
    -- new --
    newMuxbaud = cgi.post.muxbaud or "unknown"
    newMuxparity = cgi.post.muxparity or "unknown"
    newMuxdata = cgi.post.muxdata or "unknown"
    newMuxstop = cgi.post.muxstop or "unknown"
    newMuxtype = cgi.post.muxtype or "unknown"
    newXML = [[
<!-- ]]..modbusPath..[[/]]..newFile..[[ generated by webconfig -->
<device>
    <label>]]..newLabel..[[</label>
    <serial>]]..newSerial..[[</serial>
    <template>]]..newTemplate..[[</template>
    <serialport>
        <config>]]..newConfig..[[</config>
        <port>]]..newPort..[[</port>
        <owner>]]..newOwner..[[</owner>
        <slave>]]..newSlave..[[</slave>
        <muxport>]]..newMuxport..[[</muxport>
        <muxslave>]]..newMuxslave..[[</muxslave>
        <muxbaud>]]..newMuxbaud..[[</muxbaud>
        <muxparity>]]..newMuxparity..[[</muxparity>
        <muxdata>]]..newMuxdata..[[</muxdata>
        <muxstop>]]..newMuxstop..[[</muxstop>
        <muxtype>]]..newMuxtype..[[</muxtype>
    </serialport>
</device>
<!-- end of file -->
]]
    command.ex(rsm_conf.mdd_down)
    command.writefile(modbusPath..[[/]]..newFile, newXML)
    command.ex(rsm_conf.mdd_up)
    filename = newFile
    saved = 1
    mode = "edit"
else
    filename = cgi.get.file or ""
    if (filename == "") then 
        mode = "new"
    else 
        filename = filename:gsub("[^%w%.]+","")
        mode = "edit"
    end
end    

bus = cgi.get.bus or cgi.post.bus or ""

b, bCfg = serialConfig:match([[<port%s+device=%"(]]..bus..[[)%"%s->(.-)</port>]])
if (b == bus) and (bCfg ~= nil) then
    if bCfg:match("<owner>%s-mdd%s-</owner>") == nil then
        mismatch = 1
    else
        mismatch = 0
    end
else
    mismatch = 1
end

if (mode == "edit") then
    
    cfg = command.ex([[cat ]]..modbusPath..[[/]]..filename) or ""
    if (cfg:match("<device>(.+)</device>") == nil) then
        -- bail on error
        content = [[
                    <div id="info">
                        <center><h1>Edit ModBus Device</h1></center>
                    </div>            
                    <div id="info">
                        <center>
                            <h2><img src="images/warning.png"/> Invalid file</h2>
                            The specified file does not appear to be a valid ModBus device file.<br><br>
                            <a href="rsm_bus_config.lua">Back to bus configuration</a>
                        </center>
                    </div>
]]
        print(header..content..footer)
        os.exit()
    else
        d = {}
        d.label = cfg:match([[<label>%s-(.-)%s-</label>]]) or "unknown"
        d.serial = cfg:match([[<serial>%s-(.-)%s-</serial>]]) or "unknown"
        d.template = cfg:match([[<template>%s-(.-)%s-</template>]]) or "unknown"
        d.config = cfg:match([[<config>%s-(.-)%s-</config>]]) or rsm_conf.serialconfig_path
        d.port = cfg:match([[<port>%s-(.-)%s-</port>]])
        if (d.port ~= bus) then
            -- bail on error
            content = [[
                    <div id="info">
                        <center><h1>Edit ModBus Device</h1></center>
                    </div>            
                    <div id="info">
                        <center>
                            <h2><img src="images/warning.png"/> Device / bus mismatch</h2>
                            The device being edited is not on the currently selected bus.<br><br>
                            <a href="rsm_bus_config.lua">Back to bus configuration</a>
                        </center>
                    </div>
]]
            print(header..content..footer)
            os.exit()            
        end
        d.owner = "mdd"
        d.slave = cfg:match([[<slave>%s-(.-)%s-</slave>]]) or "unknown"
        d.muxport = cfg:match([[<muxport>%s-(.-)%s-</muxport>]]) or "unknown"
        d.muxslave = cfg:match([[<muxslave>%s-(.-)%s-</muxslave>]]) or "unknown"
        -- new --
        d.muxbaud = cfg:match([[<muxbaud>%s-(.-)%s-</muxbaud>]]) or "unknown"
        d.muxparity = cfg:match([[<muxparity>%s-(.-)%s-</muxparity>]]) or "unknown"
        d.muxdata = cfg:match([[<muxdata>%s-(.-)%s-</muxdata>]]) or "unknown"
        d.muxstop = cfg:match([[<muxstop>%s-(.-)%s-</muxstop>]]) or "unknown"
        d.muxtype = cfg:match([[<muxtype>%s-(.-)%s-</muxtype>]]) or "unknown"
    end
else
    d = {}
    d.label = ""
    d.serial = "(unassigned)"
    d.template = ""
    d.config = rsm_conf.serialconfig_path
    d.port = bus
    d.owner = "mdd"
    d.slave = ""
    d.muxport = ""
    d.muxslave = ""
    -- new --
    d.muxbaud = ""
    d.muxparity = ""
    d.muxdata = ""
    d.muxstop = ""
    d.muxtype = ""
end

templatesOptions = [[
                                        <option disabled ]] if (mode == "new") then templatesOptions = templatesOptions..[[selected]] end templatesOptions = templatesOptions..[[>Select a template</option>
]]

foundTemplate = 0
if (#(templatesFiles) > 0) then
    for i,f in pairs(templatesFiles) do
       templateXML = command.ex("cat "..templatesPath..[[/]]..f)
        details = templateXML:match("<details>%s-(.-)%s-</details>") or nil
        make = templateXML:match("<make>%s-(.-)%s-</make>") or ""
        model = templateXML:match("<model>%s-(.-)%s-</model>") or ""
        mType = templateXML:match("<type>%s-(.-)%s-</type>") or ""
        version = templateXML:match("<version>%s-(.-)%s-</version>") or ""
        if (version ~= "") then version = "("..version..")" end
    
        templatesOptions = templatesOptions..[[
                                        <option value="]]..f..[["]] 
                                        if f == d.template then 
                                             templatesOptions = templatesOptions .. [[ selected ]] 
                                             foundTemplate = 1 
                                        end 
                                        if details == nil then
                                             templatesOptions = templatesOptions..[[>]]..f
                                             log(f.." without details")
                                        else
                                             templatesOptions = templatesOptions..[[>]]..mType.." "..make.." "..model.." "..version
                                             log(f.." with all the details")
                                        end
                                        templatesOptions = templatesOptions..[[</option>
                                            
]]            
    end
else
        templatesOptions = [[
                                        <option disabled selected>No templates found</option>
]]
    foundTemplate = 1 -- Yeah this looks like it doesn't make sense, but it does
end
if (foundTemplate == 0) and (mode ~= "new") then
    templatesOptions = templatesOptions .. [[
                                        <option value="]]..d.template..[[" selected title="Template not found!">Template not found (]]..d.template..[[)</template>
]]        
end

content = ""

if (mode == "new") then
    content = content .. [[
                    <div id="info">
                        <div style="background:url(images/busconfig.png); background-size:32px; background-repeat:no-repeat; background-position: 20px center;">
                            <center><h1>Add New ModBus Device</h1></center>
                        </div>
                    </div>
]]
else
    content = content .. [[
                    <div id="info">
                        <div style="background:url(images/busconfig.png); background-size:32px; background-repeat:no-repeat; background-position: 20px center;">
                            <center><h1>Edit ModBus Device</h1></center>
                        </div>
                    </div>
                    <h3>Editing device "]]..d.label..[[" with filename "]]..filename..[[" :</h3>
]]    
end

if (mismatch == 1) then
    -- Bail on error here
    content = [[
                    <div id="info">
                        <center>
                            <h2><img src="images/warning.png"/> Invalid bus</h2>
                            Either an invalid bus was specified, or the bus cannot be matched<br>
                            to a valid ModBus entry in the serial config file "]]..rsm_conf.serialconfig_path..[[".<br><br>
                            <a href="rsm_bus_config.lua">Back to bus configuration</a>
                        </center>
                    </div>
]]
    html = header..content..footer
    print(html)
    os.exit()
end

if (userLevel == 1) then
    content = content .. [[
                    <center><b>Note:</b> Editing this section requires administrator privileges.</center><br>
]]
end

baudOptions = [[
                                            <option value="50">50</option>
                                            <option value="75">75</option>
                                            <option value="110">110</option>
                                            <option value="134.5">134.5</option>
                                            <option value="150">150</option>
                                            <option value="200">200</option>
                                            <option value="300">300</option>
                                            <option value="600">600</option>
                                            <option value="1200">1200</option>
                                            <option value="1800">1800</option>
                                            <option value="2400">2400</option>
                                            <option value="3600">3600</option>
                                            <option value="4800">4800</option>
                                            <option value="7200">7200</option>
                                            <option value="9600">9600</option>
                                            <option value="14400">14400</option>
                                            <option value="19200">19200</option>
                                            <option value="38400">38400</option>
                                            <option value="57600">57600</option>
                                            <option value="115200">115200</option>
]]
baudChanged = 0
baudOptions, baudChanged = baudOptions:gsub([[(<option value="]]..d.muxbaud..[[">]]..d.muxbaud..[[</option>)]], [[<option value="]]..d.muxbaud..[[" selected>]]..d.muxbaud..[[</option>]])
if (baudChanged == 0) then
    baudOptions = baudOptions:gsub([[(<option value="115200">115200</option>)]], [[<option value="115200" selected>115200</option>]])
end

parityOptions1 = ""
parityOptions2 = ""
parityOptions3 = ""
parityOptions4 = ""
parityOptions5 = ""

if (d.muxparity == "E") then
    parityOptions2 = " selected"
elseif (d.muxparity == "O") then
    parityOptions3 = " selected"
elseif (d.muxparity == "M") then
    parityOptions4 = " selected"
elseif (d.muxparity == "S") then
    parityOptions5 = " selected"
else
    parityOptions1 = " selected"
end

parityOptions = [[
                                            <option value="N"]]..parityOptions1..[[>None</option>
                                            <option value="E"]]..parityOptions2..[[>Even</option>
                                            <option value="O"]]..parityOptions3..[[>Odd</option>
                                            <option value="M"]]..parityOptions4..[[>Mark</option>
                                            <option value="S"]]..parityOptions5..[[>Space</option>
]]

dataOptions = [[
                                            <option value="5">5</option>
                                            <option value="6">6</option>
                                            <option value="7">7</option>
                                            <option value="8">8</option>
]]
dataChanged = 0
dataOptions, dataChanged = dataOptions:gsub([[(<option value="]]..d.muxdata..[[">]]..d.muxdata..[[</option>)]], [[<option value="]]..d.muxdata..[[" selected>]]..d.muxdata..[[</option>]])
if (dataChanged == 0) then
    dataOptions = dataOptions:gsub([[(<option value="8">8</option>)]], [[<option value="8" selected>8</option>]])
end

stopOptions = [[
                                            <option value="1">1</option>
                                            <option value="1.5">1.5</option>
                                            <option value="2">2</option>
]]
stopChanged = 0
stopOptions, stopChanged = stopOptions:gsub([[(<option value="]]..d.muxstop..[[">]]..d.muxstop..[[</option>)]], [[<option value="]]..d.muxstop..[[" selected>]]..d.muxstop..[[</option>]])
if (stopChanged == 0) then
    stopOptions = stopOptions:gsub([[(<option value="1">1</option>)]], [[<option value="1" selected>1</option>]])
end

typeOptions1 = ""
typeOptions2 = ""
typeOptions3 = ""

if (d.muxtype == "rs485") then
    typeOptions2 = " selected"
elseif (d.muxtype == "4wire") then
    typeOptions3 = " selected"
else
    typeOptions1 = " selected"
end

typeOptions = [[
                                            <option value="rs232"]]..typeOptions1..[[>RS232</option>
                                            <option value="rs485"]]..typeOptions2..[[>RS485</option>
                                            <option value="4wire"]]..typeOptions3..[[>Four Wire</option>
]]


content = content .. [[
                    <script>
                        var doValidate = 0;
                        function validateForm(form)
                        {
                            
                            if (form.getAttribute('submitted')) return false;
                            
                            if (!doValidate)
                            {
                                form.setAttribute('submitted','true');
                                return true;
                            }
                            doValidate = 0;
                            
                            var inputs = form.getElementsByTagName("input");
                            
                            var loop;
                            var errors = 0;
                            for (loop = 0; loop < 4; loop++)
                            {
                                var warning = document.getElementById("warning"+loop);
                                if (inputs[loop].value == "")
                                {
                                    if (!warning)
                                    {
                                        warning = document.createElement("span");
                                        warning.id = "warning"+loop;
                                        warning.innerHTML = " <img src='images/warning.png' alt='Cannot be blank' title='Cannot be blank'/>";
                                        inputs[loop].parentNode.appendChild(warning);
                                    }
                                    errors++;
                                }
                                else
                                {
                                    if (warning)
                                    {
                                        warning.parentNode.removeChild(warning);
                                    }
                                }
                            }
                            
                            var template = document.getElementById("template");
                            warning = document.getElementById("templatewarning");                            
                            if (template.value == "Select a template")
                            {
                                if (!warning)
                                {
                                    warning = document.createElement("span");
                                    warning.id = "templatewarning";
                                    warning.innerHTML = " <img src='images/warning.png' alt='Choose a valid templatek' title='Choose a valid template'/>";
                                    template.parentNode.appendChild(warning);
                                }
                                errors++;
                            }
                            else
                            {
                                if (warning)
                                {
                                    warning.parentNode.removeChild(warning);
                                }
                            }
                            
                            if (errors)
                            {
                                alert("Not all fields have been filled in.\nPlease enter/select valid values for the indicated fields.");
                                return false;
                            }
                            else
                            {
                                form.setAttribute('submitted','true');
                                return true;
                            }
                        }
                    
                    </script>
                    
                    <form action="rsm_modbus_edit.lua" method="post" onsubmit="return validateForm(this);">
                        <div class="formLayoutfull">
                            <table class="onetwo">
                                <tr>
                                    <td style="padding: 5px;" width="50%">
                                        <b>Device Label:</b>
                                    </td>
                                    <td style="padding: 5px;" width="50%">
                                        <input type="text" name="label" value="]]..d.label..[["]]..inputControl..[[ id="label"/>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Device Serial:</b>
                                    </td>
                                    <td style="padding: 5px;">]]..d.serial..[[</td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>ModBus:</b>
                                    </td>
                                    <td style="padding: 5px;">]]..bus..[[</td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Template File:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <select name="template"]]..buttonControl..[[ id="template">
]]
content = content .. templatesOptions
content = content .. [[
                                        </select>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Device Address:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <input type="text" name="slave" value="]]..d.slave..[["]]..inputControl..[[ id="slave"/>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Serial Config:</b>
                                    </td>
                                    <td style="padding: 5px;">]]..d.config..[[</td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Gateway Address:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <input type="text" name="muxslave" value="]]..d.muxslave..[["]]..inputControl..[[ id="muxslave"/>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Gateway Port:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <input type="text" name="muxport" value="]]..d.muxport..[["]]..inputControl..[[ id="muxport"/>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Mux Baud:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <select name="muxbaud"]]..buttonControl..[[>
]] .. baudOptions .. [[                                        
                                        </select>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Mux Parity:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <select name="muxparity"]]..buttonControl..[[>
]] .. parityOptions .. [[                                        
                                        </select>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Mux Data:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <select name="muxdata"]]..buttonControl..[[>
]] .. dataOptions .. [[                                        
                                        </select>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Mux Stop:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <select name="muxstop"]]..buttonControl..[[>
]] .. stopOptions .. [[                                        
                                        </select>
                                    </td>
                                </tr>
                                <tr>
                                    <td style="padding: 5px;">
                                        <b>Mux Type:</b>
                                    </td>
                                    <td style="padding: 5px;">
                                        <select name="muxtype"]]..buttonControl..[[>
]] .. typeOptions .. [[                                        
                                        </select>
                                    </td>
                                </tr>
                            </table>
                            <br>
                            <hr>
                            <br>
]]
if (saved == 1) then
    if (createdNew == 1) then
        content = content .. [[
                            <b><img src="images/ok.png"/> Saved new device with serial ]]..d.serial..[[</b><br><br>
]]
    else
        content = content .. [[
                            <b><img src="images/ok.png"/> Changes saved.</b><br><br>
]]            
    end
end
content = content .. [[
                            <input type="hidden" name="config" value="]]..d.config..[["/>
                            <input type="hidden" name="bus" value="]]..bus..[["/>
                            <input type="hidden" name="file" value="]]..filename..[["/>
                            <input type="button" name="backButton" value="Back to ModBus" onclick="window.location.assign('rsm_modbus_config.lua?bus=]]..bus..[[');"/>
                            <input type="submit" name="saveButton" value="Save and Apply"]]..buttonControl..[[ onclick="doValidate = 1;"/>
]]
if (mode == "edit") then
    content = content .. [[
                            <input type="submit" name="deleteButton" value="Delete Device"]]..buttonControl..[[ onclick="return confirm('Are you sure you want to delete this device?');"/>
]]
end
content = content .. [[
                        </form>
                    </div>
                    
]]    

if (mode == "edit") then
    cfg = cfg:gsub("<","&lt;")
    cfg = cfg:gsub(">","&gt;")
    content = content .. [[    
                    <script>
                        function toggleVis(target)
                        {
                            if (target.style.display == "none")
                            {
                                target.style.display = "inline-block";
                            }
                            else
                            {
                                target.style.display = "none";
                            }
                            return false;
                        }
                    </script>
                    <br><img src="images/magnify.png"/> <a href="javascript:void(0)" onclick="toggleVis(document.getElementById('filecfg'));">View ]]..modbusPath..[[/]]..filename..[[</a></a><br>
        
                    <div id="filecfg" style="display: none;">
                        <pre class="formLayoutfull">
]]..cfg..[[
                        </pre>
                    </div>    
]]
end


print(header..content..footer)
