# Copyright 2013 OpenStack Foundation
#
# 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.

import sqlalchemy as sql

from keystone.common import utils
from keystone import exception
from keystone.openstack.common.gettextutils import _


def upgrade(migrate_engine):
    meta = sql.MetaData()
    meta.bind = migrate_engine

    credential_table = sql.Table('credential',
                                 meta,
                                 autoload=True)

    ec2_cred_table = sql.Table('ec2_credential',
                               meta,
                               autoload=True)

    session = sql.orm.sessionmaker(bind=migrate_engine)()
    insert = credential_table.insert()
    for ec2credential in session.query(ec2_cred_table):
        cred_exist = check_credential_exists(ec2credential,
                                             credential_table, session)

        if not cred_exist:
            credential = utils.convert_ec2_to_v3_credential(ec2credential)
            insert.execute(credential)

    session.commit()
    session.close()

    ec2_cred_table.drop()


def check_credential_exists(ec2credential, credential_table, session):
    credential = session.query(credential_table).filter_by(
        id=utils.hash_access_key(ec2credential.access)).first()
    if credential is None:
        return False
    blob = utils.get_blob_from_credential(credential)
    # check if credential with same access key but different
    # secret key already exists in credential table.
    # If exists raise an exception
    if blob['secret'] != ec2credential.secret:
        msg = _('Credential %(access)s already exists with different secret'
                ' in %(table)s table')
        message = msg % {'access': ec2credential.access,
                         'table': credential_table.name}
        raise exception.Conflict(type='credential', details=message)
    # check if credential with same access and secret key but
    # associated with a different project exists. If exists raise
    # an exception
    elif credential.project_id is not None and (
            credential.project_id != ec2credential.tenant_id):
        msg = _('Credential %(access)s already exists with different project'
                ' in %(table)s table')
        message = msg % {'access': ec2credential.access,
                         'table': credential_table.name}
        raise exception.Conflict(type='credential', details=message)
    # if credential with same access and secret key and not associated
    # with any projects already exists in the credential table, then
    # return true.
    else:
        return True


def downgrade(migrate_engine):
    meta = sql.MetaData()
    meta.bind = migrate_engine

    session = sql.orm.sessionmaker(bind=migrate_engine)()

    ec2_credential_table = sql.Table(
        'ec2_credential',
        meta,
        sql.Column('access', sql.String(64), primary_key=True),
        sql.Column('secret', sql.String(64)),
        sql.Column('user_id', sql.String(64)),
        sql.Column('tenant_id', sql.String(64)),
        mysql_engine='InnoDB',
        mysql_charset='utf8')

    ec2_credential_table.create(migrate_engine, checkfirst=True)
    credential_table = sql.Table('credential',
                                 meta,
                                 autoload=True)
    insert = ec2_credential_table.insert()
    for credential in session.query(credential_table).filter(
            sql.and_(credential_table.c.type == 'ec2',
                     credential_table.c.project_id is not None)).all():
        ec2_credential = utils.convert_v3_to_ec2_credential(credential)
        insert.execute(ec2_credential)

    session.commit()
    session.close()
