/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * 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.
 */

package com.android.sdklib.repository.legacy.descriptors;

import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.repository.Revision;
import com.android.repository.api.License;
import com.android.repository.api.RepoManager;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.repository.AndroidSdkHandler;
import com.android.sdklib.repository.IdDisplay;

/**
 * Implementation detail of {@link IPkgDescExtra} for extra packages.
 *
 * @deprecated This is part of the old SDK manager framework. Use
 * {@link AndroidSdkHandler}/{@link RepoManager} and associated classes instead.
 */
@Deprecated
public final class PkgDescExtra extends PkgDesc implements IPkgDescExtra {

    private final String[] mOldPaths;

    PkgDescExtra(@NonNull PkgType type,
                 @Nullable License license,
                 @Nullable String listDisplay,
                 @Nullable String descriptionShort,
                 @Nullable String descriptionUrl,
                 boolean isObsolete,
                 @Nullable Revision revision,
                 @Nullable AndroidVersion androidVersion,
                 @Nullable String path,
                 @Nullable IdDisplay tag,
                 @Nullable IdDisplay vendor,
                 @Nullable Revision minToolsRev,
                 @Nullable Revision minPlatformToolsRev,
                 @Nullable  String nameDisplay,
                 @Nullable final String[] oldPaths) {
        super(type,
                license,
                listDisplay,
                descriptionShort,
                descriptionUrl,
                isObsolete,
                revision,
                androidVersion,
                path,
                tag,
                vendor,
                minToolsRev,
                minPlatformToolsRev,
                null,     //customIsUpdateFor
                null,
                IdDisplay.create(nameDisplay == null ? "" : nameDisplay,
                        nameDisplay == null ? "" : nameDisplay));
        mOldPaths = oldPaths != null ? oldPaths : new String[0];
    }

    @NonNull
    @Override
    public String[] getOldPaths() {
        return mOldPaths;
    }

    @NonNull
    @Override
    public String getNameDisplay() {
        return getName() == null || getName().getDisplay() == null ? String
                .format("Unknown (%s)", getInstallId()) : getName().getDisplay();
    }

    // ---- Helpers ----

    /**
     * Helper method that converts the old_paths property string into the
     * an old paths array.
     *
     * @param oldPathsProperty A possibly-null old_path property string.
     * @return A list of old paths split by their separator. Can be empty but not null.
     */
    @NonNull
    public static String[] convertOldPaths(@Nullable String oldPathsProperty) {
        if (oldPathsProperty == null || oldPathsProperty.isEmpty()) {
            return new String[0];
        }
        return oldPathsProperty.split(";");  //$NON-NLS-1$
    }

    /**
     * Helper to computhe whether the extra path of both {@link IPkgDescExtra}s
     * are compatible with each other, which means they are either equal or are
     * matched between existing path and the potential old paths list.
     * <p>
     * This also covers backward compatibility -- in earlier schemas the vendor id was
     * merged into the path string when reloading installed extras.
     *
     * @param lhs A non-null {@link IPkgDescExtra}.
     * @param rhs Another non-null {@link IPkgDescExtra}.
     * @return true if the paths are compatible.
     */
    public static boolean compatibleVendorAndPath(
            @NonNull IPkgDescExtra lhs,
            @NonNull IPkgDescExtra rhs) {
        String[] epOldPaths = rhs.getOldPaths();
        int lenEpOldPaths = epOldPaths.length;
        for (int indexEp = -1; indexEp < lenEpOldPaths; indexEp++) {
            if (sameVendorAndPath(
                    lhs.getVendor().getId(), lhs.getPath(),
                    rhs.getVendor().getId(), indexEp < 0 ? rhs.getPath() : epOldPaths[indexEp])) {
                return true;
            }
        }

        String[] thisOldPaths = lhs.getOldPaths();
        int lenThisOldPaths = thisOldPaths.length;
        for (int indexThis = -1; indexThis < lenThisOldPaths; indexThis++) {
            if (sameVendorAndPath(
                 lhs.getVendor().getId(), indexThis < 0 ? lhs.getPath() : thisOldPaths[indexThis],
                 rhs.getVendor().getId(), rhs.getPath())) {
                return true;
            }
        }

        return false;
    }

    private static boolean sameVendorAndPath(
            @Nullable String thisVendor,  @Nullable String thisPath,
            @Nullable String otherVendor, @Nullable String otherPath) {
        // To be backward compatible, we need to support the old vendor-path form
        // in either the current or the remote package.
        //
        // The vendor test below needs to account for an old installed package
        // (e.g. with an install path of vendor-name) that has then been updated
        // in-place and thus when reloaded contains the vendor name in both the
        // path and the vendor attributes.
        if (otherPath != null && thisPath != null && thisVendor != null) {
            if (otherPath.equals(thisVendor + '-' + thisPath) &&
                    (otherVendor == null ||
                            otherVendor.isEmpty() ||
                     otherVendor.equals(thisVendor))) {
                return true;
            }
        }
        if (thisPath != null && otherPath != null && otherVendor != null) {
            if (thisPath.equals(otherVendor + '-' + otherPath) &&
                    (thisVendor == null ||
                            thisVendor.isEmpty() ||
                     thisVendor.equals(otherVendor))) {
                return true;
            }
        }


        if (thisPath != null && thisPath.equals(otherPath)) {
            if ((thisVendor == null && otherVendor == null) ||
                (thisVendor != null && thisVendor.equals(otherVendor))) {
                return true;
            }
        }

        return false;
    }

}

