#!/usr/bin/env python

# vim: tabstop=4 shiftwidth=4 softtabstop=4

# Copyright 2013 Violin Memory, Inc.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.

# Get our library version
try:
    import cinder.volume.drivers.violin.vxg.version
    __version__ = cinder.volume.drivers.violin.vxg.version.__version__
except Exception:
    # version.py is autogenerated during packaging. If we are running
    # against original source it will not be present.
    __version__ = "unknown"


import sys

# Require python 2.6.0
# Use hexversion for arithmatic comparison versus major-minor-micro tuple
if sys.hexversion <= 0x02060000:
    raise ImportError("Requires python 2.6.  Running python %d.%d.%d." %
                      (sys.version_info[0], sys.version_info[1],
                       sys.version_info[2]))

import inspect

from cinder.volume.drivers.violin.vxg.core.session import XGSession
from cinder.volume.drivers.violin.vxg.varray import varray
from cinder.volume.drivers.violin.vxg.vshare import vshare

__VERSION_MULTIPLIER = 1000


def open(host, user='admin', password='',
         proto='https', version=1, debug=False):
    """
    Opens up a XML Gateway session with the given Violin Memory appliance.

    This will first login to the given host, then access that host's version
    node registration.  Depending on what the host identifies itself as, an
    object compatible with that particular version will be returned.

    If there are any problems (such as auth failure or inaccessible hostname),
    then None will be returned.

    Arguments:
        host     -- Name or IP address of the host to connect to
        user     -- Username to login with
        password -- Password for the user
        proto    -- Either 'http' or 'https' (default: https)
        version  -- Reserved for future use
        debug    -- Enable/disable debugging to stdout (bool)

    Returns:
        A VArray or VShare object, automatically authenticated, depending
        on what is encountered for the given host.  If there are any problems,
        then None is returned.

    """
    returnObject = None
    moduleToSearch = None
    session = XGSession(host, user, password, debug, proto, False)

    if session.login():
        node = '/system/version/release'
        version = session.get_node_values([node])[node]
        if debug:
            print("Version:  %s" % (version,))
        hostType = version[0]
        if hostType == 'A':
            returnObject = __getDeviceFor(version, session, varray, debug)
        elif hostType in 'VG':
            returnObject = __getDeviceFor(version, session, vshare, debug)

    return returnObject


def __getDeviceFor(versionString, session, moduleToSearch, debug):
    version = __dottedVersionToInt(versionString)
    vlist = []

    for name, obj in inspect.getmembers(moduleToSearch):
        if (inspect.isclass(obj) and name.find(
                moduleToSearch.CLASS_NAMES) > -1):
            if isinstance(obj.versions, basestring):
                vlist.append({__dottedVersionToInt(obj.versions): obj, })
            elif isinstance(obj.versions, list):
                for x in obj.versions:
                    vlist.append({__dottedVersionToInt(x): obj, })
            else:
                raise Exception('Unknown version type' +
                                '%s ' % (obj.versions.__class__,) +
                                'encountered in ' +
                                'class %s.' % (name,))

    vlist.sort(__mycmp, reverse=True)

    for x in vlist:
        objVersion, obj = x.items()[0]
        if version >= objVersion:
            return obj(session)
    else:
        print("No matching version for %s" % (versionString,))
        return session


def __mycmp(a, b):
    anum = a.keys()[0]
    bnum = b.keys()[0]
    if anum < bnum:
        return -1
    elif anum == bnum:
        return 0
    else:
        return 1


def __dottedVersionToInt(version):
    vlist = version.split('.')
    if not vlist[0].isdigit():
        vlist[0] = vlist[0].lstrip('AGV')
        if not vlist[0].isdigit():
            print("Unknown version: %s" % (version,))
            return None

    vint = int(vlist[2]) + \
        int(vlist[1]) * __VERSION_MULTIPLIER + \
        int(vlist[0]) * __VERSION_MULTIPLIER * __VERSION_MULTIPLIER

    return vint
