"""
    Credit: https://github.com/jundongl/scikit-feature
"""
import numpy as np
import feature_extraction_image_preprocessing as feature
from scipy.sparse import *
from skfeature.utility.construct_W import construct_W


def fisher_score(X, y):
    """
    This function implements the fisher score feature selection, steps are as follows:
    1. Construct the affinity matrix W in fisher score way
    2. For the r-th feature, we define fr = X(:,r), D = diag(W*ones), ones = [1,...,1]', L = D - W
    3. Let fr_hat = fr - (fr'*D*ones)*ones/(ones'*D*ones)
    4. Fisher score for the r-th feature is score = (fr_hat'*D*fr_hat)/(fr_hat'*L*fr_hat)-1

    Input
    -----
    X: {numpy array}, shape (n_samples, n_features)
        input data
    y: {numpy array}, shape (n_samples,)
        input class labels

    Output
    ------
    score: {numpy array}, shape (n_features,)
        fisher score for each feature

    Reference
    ---------
    He, Xiaofei et al. "Laplacian Score for Feature Selection." NIPS 2005.
    Duda, Richard et al. "Pattern classification." John Wiley & Sons, 2012.
    """

    # Construct weight matrix W in a fisherScore way
    kwargs = {"neighbor_mode": "supervised", "fisher_score": True, 'y': y}
    W = construct_W(X, **kwargs)

    # build the diagonal D matrix from affinity matrix W
    D = np.array(W.sum(axis=1))
    L = W
    tmp = np.dot(np.transpose(D), X)
    D = diags(np.transpose(D), [0])
    Xt = np.transpose(X)
    t1 = np.transpose(np.dot(Xt, D.todense()))
    t2 = np.transpose(np.dot(Xt, L.todense()))
    # compute the numerator of Lr
    D_prime = np.sum(np.multiply(t1, X), 0) - np.multiply(tmp, tmp)/D.sum()
    # compute the denominator of Lr
    L_prime = np.sum(np.multiply(t2, X), 0) - np.multiply(tmp, tmp)/D.sum()
    # avoid the denominator of Lr to be 0
    D_prime[D_prime < 1e-12] = 10000
    lap_score = 1 - np.array(np.multiply(L_prime, 1/D_prime))[0, :]

    # compute fisher score from laplacian score, where fisher_score = 1/lap_score - 1
    score = 1.0/lap_score - 1
    return np.transpose(score)


def feature_ranking(score):
    """
    Rank features in descending order according to fisher score, the larger the fisher score, the more important the
    feature is
    """
    idx = np.argsort(score, 0)
    return idx[::-1]


if __name__ == '__main__':
    gray_scale_feature = feature.getFeature('gray_scale')
    label = []
    data = []
    for i in gray_scale_feature:
        label.append(i[0])
        data.append(i[1])
    label = np.asarray(label)
    gray_scale_fisher_score = fisher_score(data, label)
    gray_scale_fisher_score = feature_ranking(gray_scale_fisher_score)
    print(f'Gray scale fisher score: {gray_scale_fisher_score[0]}')

    mean_pixel_feature = feature.getFeature('mean_pixel')
    data = []
    for i in mean_pixel_feature:
        data.append(i[1])
    mean_pixel_fisher_score = fisher_score(data, label)
    mean_pixel_fisher_score = feature_ranking(mean_pixel_fisher_score)
    print(f'Mean fisher score: {mean_pixel_fisher_score[0]}')

    extracting_edge_horizontal_feature = feature.getFeature('extracting_edge_horizontal')
    data = []
    for i in extracting_edge_horizontal_feature:
        data.append(i[1])
    extracting_edge_horizontal_fisher_score = fisher_score(data, label)
    extracting_edge_horizontal_fisher_score = feature_ranking(extracting_edge_horizontal_fisher_score)
    print(f'Horizontal fisher score: {extracting_edge_horizontal_fisher_score[0]}')

    extracting_edge_vertical_feature = feature.getFeature('extracting_edge_vertical')
    data = []
    for i in extracting_edge_vertical_feature:
        data.append(i[1])
    extracting_edge_vertical_fisher_score = fisher_score(data, label)
    extracting_edge_vertical_fisher_score = feature_ranking(extracting_edge_vertical_fisher_score)
    print(f'Vertical fisher score: {extracting_edge_vertical_fisher_score[0]}')

    hog_feature = feature.getFeature('hog')
    data = []
    for i in hog_feature:
        data.append(i[1])
    hog_fisher_score = fisher_score(data, label)
    hog_fisher_score = feature_ranking(hog_fisher_score)
    print(f'HOG fisher score: {hog_fisher_score[0]}')
