# -*- coding: utf-8 -*-
"""
SeisComp XML function used for both inventory and event module.

:author:
    EOST (École et Observatoire des Sciences de la Terre)
:copyright:
    The ObsPy Development Team (devs@obspy.org)
:license:
    GNU Lesser General Public License, Version 3
    (https://www.gnu.org/copyleft/lesser.html)
"""
import os
import re

from lxml import etree

from obspy.core.util.decorator import deprecated
from obspy.io.quakeml.core import _xml_doc_from_anything


# SCML version for which an XSD file is available
SCHEMA_VERSION = ['0.7', '0.8', '0.9', '0.10',
                  '0.11', '0.12', '0.13', '0.14']
# from version 0.14 onwards "sc3ml" is dropped
NEW_SCHEMA_VERSION = ['0.14']


# deprecated with 1.5.0, remove a few main releases later
@deprecated(
    'Deprecated and will be removed next release, use _is_scml() instead')
def _is_sc3ml(*args, **kwargs):
    return _is_scml(*args, **kwargs)


def _is_scml(path_or_file_object):
    """
    Simple function checking if the passed object contains a valid SCML file
    according to the list of versions given in parameters. Returns True of
    False.

    The test is not exhaustive - it only checks the root tag but that should
    be good enough for most real world use cases. If the schema is used to
    test for a StationXML file, many real world files are false negatives as
    they don't adhere to the standard.

    :type path_or_file_object: str
    :param path_or_file_object: File name or file like object.
    :rtype: bool
    :return: `True` if file is a SCML file.
    """
    if hasattr(path_or_file_object, "tell") and hasattr(path_or_file_object,
                                                        "seek"):
        current_position = path_or_file_object.tell()

    if isinstance(path_or_file_object, etree._Element):
        xmldoc = path_or_file_object
    else:
        try:
            xmldoc = _xml_doc_from_anything(path_or_file_object)
        except ValueError:
            return False
        finally:
            # Make sure to reset file pointer position.
            try:
                path_or_file_object.seek(current_position, 0)
            except Exception:
                pass

    if hasattr(xmldoc, "getroot"):
        root = xmldoc.getroot()
    else:
        root = xmldoc

    match = re.match(
        r'{http://geofon\.gfz(?:-potsdam)?\.de/ns/seiscomp3?-schema/([-+]?'
        r'[0-9]*\.?[0-9]+)}', root.tag)

    return match is not None


def validate(path_or_object, version=None, verbose=False):
    """
    Check if the given file is a valid SCML file.

    :type path_or_object: str
    :param path_or_object: File name or file like object. Can also be an etree
        element.
    :type version: str
    :param version: Version of the SCML schema to validate against.
    :type verbose: bool
    :param verbose: Print error log if True.
    :rtype: bool
    :return: `True` if SCML file is valid.
    """
    if hasattr(path_or_object, "tell") and hasattr(path_or_object, "seek"):
        current_position = path_or_object.tell()

    if isinstance(path_or_object, etree._Element):
        xmldoc = path_or_object
    else:
        try:
            xmldoc = _xml_doc_from_anything(path_or_object)
        except ValueError:
            return False
        finally:
            # Make sure to reset file pointer position.
            try:
                path_or_object.seek(current_position, 0)
            except Exception:
                pass

    # Read version number from file
    if version is None:
        match = re.match(
            r'{http://geofon\.gfz(?:-potsdam)?\.de/ns/seiscomp3?-schema/([-+]?'
            r'[0-9]*\.?[0-9]+)}', xmldoc.tag)
        try:
            version = match.group(1)
        except AttributeError:
            raise ValueError("Not a SCML compatible file or string.")

    if version not in SCHEMA_VERSION:
        raise ValueError('%s is not a supported version. Use one of these '
                         'versions: [%s].'
                         % (version, ', '.join(SCHEMA_VERSION)))

    # Get the schema location.
    if version in NEW_SCHEMA_VERSION:
        xsd_filename = 'scml_%s.xsd' % version
    else:
        xsd_filename = 'sc3ml_%s.xsd' % version
    schema_location = os.path.join(os.path.dirname(__file__), 'data',
                                   xsd_filename)
    xmlschema = etree.XMLSchema(etree.parse(schema_location))

    valid = xmlschema.validate(xmldoc)

    # Pretty error printing if the validation fails.
    if verbose and valid is not True:
        print("Error validating SCML file:")
        for entry in xmlschema.error_log:
            print("\t%s" % entry)

    return valid
