# -*- coding: utf-8 -*-
#
# Copyright (C) 2019 Apple Inc.  All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


# Class for representing SDK information, in the form of Platform, Version, and
# whether or not it's an Internal SDK. This class also contains a factory
# method for producing an SDK instance from a "specification" string such as
# "macOS15.3Internal", like you would get from 'xcodebuild -showsdks".


import re

from webkitpy.common.system.executive import Executive


test_output = None


class SDK(object):
    __slots__ = ["xcode_specification", "platform", "version", "internal"]

    def __init__(self, xcode_specification, platform, version, internal):
        super(SDK, self).__init__()
        self.xcode_specification = xcode_specification
        self.platform = platform
        self.version = version
        self.internal = internal

    def __repr__(self):
        return "SDK({}, {}, {}, {})".format(
                self.xcode_specification,
                self.platform,
                self.version,
                self.internal)

    def as_xcode_specification(self):
        return "{}.internal".format(self.platform) if self.internal else self.platform

    @classmethod
    def get_preferred_sdk_for_platform(cls, platform, executive=None):

        preferred_sdk = cls._parse_sdk(platform)

        executive = executive or Executive()
        stdout = executive.run_command(["xcodebuild", "-showsdks"])

        for line in stdout.splitlines():
            m = re.match(r".*-sdk (.*)", line)
            if m:
                this_sdk = cls._parse_sdk(m.group(1))

                if preferred_sdk.platform != this_sdk.platform:
                    continue

                # Both have version information, so compare versions. If the
                # versions are equal, prefer the Internal sdk. Otherwise, keep
                # the one with the higher version.

                if preferred_sdk.version and this_sdk.version:
                    if float(preferred_sdk.version) == float(this_sdk.version):
                        if this_sdk.internal:
                            preferred_sdk = this_sdk
                    elif float(preferred_sdk.version) < float(this_sdk.version):
                        preferred_sdk = this_sdk

                # The preferred sdk does not have a version but the prospective
                # one does, so keep the prospective one.

                elif not preferred_sdk.version and this_sdk.version:
                    preferred_sdk = this_sdk

                # The preferred sdk has a version but the prospective one does
                # not, so keep the preferred one.

                elif preferred_sdk.version and not this_sdk.version:
                    pass

                # Neither has version information; prefer the current one if
                # it's internal.

                elif not preferred_sdk.version and not this_sdk.version:
                    if this_sdk.internal:
                        preferred_sdk = this_sdk

        return preferred_sdk

    @classmethod
    def _parse_sdk(cls, xcode_specification):
        # letters-and-dots, followed by optional numbers-and-dots, followed by
        # an optional "internal"
        m = re.match(r"([a-zA-Z.]+[a-zA-Z])([0-9.]+[0-9])?\.?(internal)?", xcode_specification)
        if not m:
            return SDK(xcode_specification, None, None, None)

        platform = m.group(1)
        version = m.group(2)
        internal = m.group(3)

        return SDK(xcode_specification, platform, version, internal)
