#!/usr/bin/python3
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
#
# Copyright (C) 2010-2012 Bryce Harrington <bryce@canonical.com>
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import absolute_import, print_function, unicode_literals

import re
import os
import sys
import fnmatch

# Add project root directory (enable symlink, and trunk execution).
PROJECT_ROOT_DIRECTORY = os.path.abspath(
    os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))

if (os.path.exists(os.path.join(PROJECT_ROOT_DIRECTORY, 'xdiagnose'))
    and PROJECT_ROOT_DIRECTORY not in sys.path):
    sys.path.insert(0, PROJECT_ROOT_DIRECTORY)
    os.putenv('PYTHONPATH', PROJECT_ROOT_DIRECTORY) # for subprocesses

from xdiagnose.edid import Edid
from xdiagnose.utils.paths import locate
from xdiagnose.utils import debug

## NVIDIA ##
#
# In Precise, -nvidia does not support writable EDID via KMS.
# However, it does provide a CustomEDID option in xorg.conf which
# servces essentially the same purpose.  To use it, you need
# a section like the following in your xorg.conf.  (I believe the
# nvidia-config GUI tool has buttons to add this for you.)
#
#Section "Device"
#    Identifier    "Device0"
#    Driver        "nvidia" #Choose the driver used for this monitor
#    Option "UseEDID" "FALSE"
#    Option "CustomEDID" "DFP-1:/etc/X11/xorg.conf.d/edid.bin"
#EndSection

# TODO: Need a corresponding edid read functionality.  (Or can we
#  just use the get-edid script from the read-edid package?)

def usage():
    print("Usage: xedid <command> [edid-sources]")
    print("")
    print("Commands:")
    print("  list [edid-src]   - List edids available on the system")
    print("  show [edid-src]   - Display decoded edid information")
    print("  save [edid-src]   - Copy active EDIDs to binary *.edid files")
    print("  raw [edid-src]    - Prints the EDID hex codes")
    print("  install <edid>    - Adds given edid file to kernel firmware")
    print("  uninstall <edid>  - Removes named edid file from firmware")
    print("  activate <edid>   - Makes kernel use given edid from firmware")
    print("")
    print("Notes:")
    print("  EDID sources (edid-src) can be Xorg.0.log files or binary or hex")
    print("  edid files.  EDID binaries (edid) must be binary files in a valid")
    print("  EDID data format.")
    print("")
    print("  The EDID firmware (located at %s) can have" %(Edid.EDID_FIRMWARE_PATH))
    print("  multiple edids installed, but only one activated at a time.  The")
    print("  activated EDID is passed to the kernel command line (configured")
    print("  at %s)." %(Edid.EDID_DRM_CONF_PATH))


if __name__ == "__main__":
    from xdiagnose import info
    from xdiagnose.utils.option_handler import OptionHandler

    opt_hand = OptionHandler(info)
    opt_hand.add('-v', '--verbose', dest="verbose",
                 help="Show debug messages",
                 action="store_true", default=False,
                 desc="Turns on verbose debugging output.")
    opts, args = opt_hand.parse_args()
    debug.DEBUGGING = opts.verbose

    if len(args) > 0:
        command = args[0]
    else:
        command = "show"

    # Handle firmware requests
    if command in ['install', 'uninstall', 'activate']:
        # Test that everything is sane
        if len(args) < 2:
            usage()
            sys.exit(2)
        elif os.getenv("USER") != "root":
            print("Error:  Must run as root")
            sys.exit(3)

        edid = Edid()
        for filename in args[1:]:
            if command == 'install':
                # TODO: Verify file(s) are valid edid
                # TODO: Move install to an EdidFirmware class
                edid.install(filename)
            elif command == 'uninstall':
                edid.uninstall(filename)
            elif command == 'activate':
                edid.activate(filename)
        sys.exit(0)

    source_files = args[1:]
    sources      = []
    for filename in args[1:]:
        edid = Edid()
        if not edid.load(filename):
            continue
        sources.append(edid)

    if len(sources) == 0:
        # Xorg.0.log
        # TODO: Handle multiple edids in the log
        xlog_edid = Edid()
        if xlog_edid.load("/var/log/Xorg.0.log"):
            sources.append(xlog_edid)

        # Kernel edid nodes
        re_lvds = re.compile(".*LVDS.*")
        # Identify what edid file sysfs nodes are present
        for node in locate('edid', root="/sys"):
            if re_lvds.match(node):
                continue
            node_edid = Edid()
            if node_edid.load(node):
                sources.append(node_edid)

    source_number = 0
    for edid in sources:
        if command == "list":
            print(edid.name)
        elif command == "show":
            print(edid)
        elif command == "save":
            filename = "%s-%s-%s.%02d.edid" %(
                edid.manufacturer,
                edid.product_id,
                edid.serial_number,
                source_number)
            if edid.save(filename):
                print(filename)
        elif command == "raw":
            for i in range(0, int(len(edid.raw)/32)):
                j = i + 1
                print(edid.raw[i*32:j*32])
            print()
        else:
            print("Unknown command '%s'" %(command))
            usage()
            sys.exit(1)
        source_number += 1

    sys.exit(0)
