import numpy as np

from features import Feature


############################################################
# Platform
############################################################

class CensusMDC2FormFactor(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_MDC2FormFactor']
        self.test[column] = test_df['Census_MDC2FormFactor']


class CensusChassisTypeName(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_ChassisTypeName']
        self.test[column] = test_df['Census_ChassisTypeName']


class CensusPowerPlatformRoleName(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_PowerPlatformRoleName']
        self.test[column] = test_df['Census_PowerPlatformRoleName']


############################################################
# OEM information
############################################################

class CensusOEMNameId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OEMNameIdentifier']
        self.test[column] = test_df['Census_OEMNameIdentifier']


class CensusOEMModelId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OEMModelIdentifier']
        self.test[column] = test_df['Census_OEMModelIdentifier']


############################################################
#  OS
############################################################

class CensusOSVersion(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSVersion']
        self.test[column] = test_df['Census_OSVersion']


class CensusOSBuildNumber(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSBuildNumber']
        self.test[column] = test_df['Census_OSBuildNumber']


class CensusOSBuildRevision(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSBuildRevision']
        self.test[column] = test_df['Census_OSBuildRevision']


class CensusOSArchitecture(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSArchitecture']
        self.test[column] = test_df['Census_OSArchitecture']


class CensusOSBranch(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSBranch']
        self.test[column] = test_df['Census_OSBranch']


class CensusOSEdition(Feature):
    def create_features_from_df(self, train_df, test_df):
        def _normalize_os_edition(x):
            x = str(x).lower()
            if 'core' in x:
                return 'Core'
            if 'professionaleducation' in x:
                return 'ProfessionalEducation'
            if 'pro' in x:
                return 'Professional'
            if 'education' in x:
                return 'Education'
            if 'enterprise' in x:
                return 'Enterprise'
            if 'server' in x:
                return 'Server'
            if 'cloud' in x:
                return 'Cloud'
            else:
                return 'Other'

        column = self.column
        self.train[column] = train_df['Census_OSEdition'].apply(_normalize_os_edition)
        self.test[column] = test_df['Census_OSEdition'].apply(_normalize_os_edition)


# NOTE: almost the same as CensusOSEdition
class CensusOSSkuName(Feature):
    def create_features_from_df(self, train_df, test_df):
        def _normalize_os_sku_name(x):
            x = str(x).lower()
            if 'core' in x:
                return 'Core'
            if 'pro' in x:
                return 'Professional'
            if 'education' in x:
                return 'Education'
            if 'enterprise' in x:
                return 'Enterprise'
            if 'server' in x:
                return 'Server'
            if 'cloud' in x:
                return 'Cloud'
            else:
                return 'Other'

        column = self.column
        self.train[column] = train_df['Census_OSSkuName'].apply(_normalize_os_sku_name)
        self.test[column] = test_df['Census_OSSkuName'].apply(_normalize_os_sku_name)


class CensusOSInstallTypeName(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSInstallTypeName']
        self.test[column] = test_df['Census_OSInstallTypeName']


class CensusOSInstallLanguageId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSInstallLanguageIdentifier']
        self.test[column] = test_df['Census_OSInstallLanguageIdentifier']


# NOTE: almost the same as CensusOSInstallLanguageId
class CensusOsUILocaleId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSUILocaleIdentifier']
        self.test[column] = test_df['Census_OSUILocaleIdentifier']


class CensusOsWUAutoUpdateOptionsName(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_OSWUAutoUpdateOptionsName']
        self.test[column] = test_df['Census_OSWUAutoUpdateOptionsName']


class CensusGenuineStateName(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_GenuineStateName']
        self.test[column] = test_df['Census_GenuineStateName']


class CensusActivationChannel(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_ActivationChannel']
        self.test[column] = test_df['Census_ActivationChannel']


############################################################
# CPU
############################################################

class CensusProcessorCoreCount(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_ProcessorCoreCount'].fillna(4.0).astype('float32')
        self.test[column] = test_df['Census_ProcessorCoreCount'].fillna(4.0).astype('float32')


class CensusProcessorManufacturerId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self._normalize(train_df)
        self._normalize(test_df)
        self.train[column] = train_df['Census_ProcessorManufacturerIdentifier']
        self.test[column] = test_df['Census_ProcessorManufacturerIdentifier']

    def _normalize(self, df):
        column = 'Census_ProcessorManufacturerIdentifier'
        df.loc[df[column].isin([5.0, 1.0]) == False, column] = 0.0


class CensusProcessorModelId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_ProcessorModelIdentifier']
        self.test[column] = test_df['Census_ProcessorModelIdentifier']


############################################################
# RAM
############################################################

class CensusTotalPhysicalRAM(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_TotalPhysicalRAM']
        self.test[column] = test_df['Census_TotalPhysicalRAM']


############################################################
# Disk
############################################################

class CensusPrimaryDiskTypeName(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self._normalize(train_df)
        self._normalize(test_df)
        self.train[column] = train_df['Census_PrimaryDiskTypeName']
        self.test[column] = test_df['Census_PrimaryDiskTypeName']

    def _normalize(self, df):
        column = 'Census_PrimaryDiskTypeName'
        df.loc[df[column].isin(['HDD', 'SSD']) == False, column] = 'UNKNOWN'


class CensusSystemVolumeTotalCapacity(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_SystemVolumeTotalCapacity']
        self.test[column] = test_df['Census_SystemVolumeTotalCapacity']


class CensusPrimaryDiskTotalCapacity(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_PrimaryDiskTotalCapacity']
        self.test[column] = test_df['Census_PrimaryDiskTotalCapacity']


class CensusPrimaryDriveCRatio(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = self._compute(train_df)
        self.test[column] = self._compute(test_df)

    def _compute(self, df):
        return (
            df['Census_SystemVolumeTotalCapacity'] /
            df['Census_PrimaryDiskTotalCapacity']
        )


class CensusNonePrimaryDriveMB(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = self._compute(train_df)
        self.test[column] = self._compute(test_df)

    def _compute(self, df):
        return (
            df['Census_PrimaryDiskTotalCapacity'] -
            df['Census_SystemVolumeTotalCapacity']
        )


############################################################
# Display
############################################################

class CensusInternalPrimaryDiagonalDisplaySizeInInches(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        column_org = 'Census_InternalPrimaryDiagonalDisplaySizeInInches'
        self.train[column] = train_df[column_org].astype('float32')
        self.test[column] = test_df[column_org].astype('float32')


class CensusInternalPrimaryDisplayResolutionHorizontal(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        column_org = 'Census_InternalPrimaryDisplayResolutionHorizontal'
        self.train[column] = train_df[column_org].astype('float32')
        self.test[column] = test_df[column_org].astype('float32')


class CensusInternalPrimaryDisplayResolutionVertical(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        column_org = 'Census_InternalPrimaryDisplayResolutionVertical'
        self.train[column] = train_df[column_org].astype('float32')
        self.test[column] = test_df[column_org].astype('float32')


class CensusAspectRatio(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = self._compute(train_df)
        self.test[column] = self._compute(test_df)

    def _compute(self, df):
        return (
            df['Census_InternalPrimaryDisplayResolutionHorizontal'] /
            df['Census_InternalPrimaryDisplayResolutionVertical']
        )


class CensusMonitorDotsPerInch(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = self._compute(train_df)
        self.test[column] = self._compute(test_df)

    def _compute(self, df):
        return (
            (df['Census_InternalPrimaryDisplayResolutionHorizontal'] **2 +
             df['Census_InternalPrimaryDisplayResolutionVertical'] **2) ** 0.5 /
            df['Census_InternalPrimaryDiagonalDisplaySizeInInches']
        )


class CensusDisplayMegaPixels(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = self._compute(train_df)
        self.test[column] = self._compute(test_df)

    def _compute(self, df):
        return (
            df['Census_InternalPrimaryDisplayResolutionHorizontal'] *
            df['Census_InternalPrimaryDisplayResolutionVertical'] / 1e6
        )


############################################################
# Firmware
############################################################

class CensusFirmwareManufacturerId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_FirmwareManufacturerIdentifier']
        self.test[column] = test_df['Census_FirmwareManufacturerIdentifier']


class CensusFirmwareVersionId(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_FirmwareVersionIdentifier']
        self.test[column] = test_df['Census_FirmwareVersionIdentifier']


############################################################
# misc.
############################################################

class CensusIsSecureBootEnabled(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_IsSecureBootEnabled']
        self.test[column] = test_df['Census_IsSecureBootEnabled']


class CensusIsTouchEnabled(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_IsTouchEnabled']
        self.test[column] = test_df['Census_IsTouchEnabled']


class CensusIsAlwaysOnAlwaysConnectedCapable(Feature):
    def create_features_from_df(self, train_df, test_df):
        column = self.column
        self.train[column] = train_df['Census_IsAlwaysOnAlwaysConnectedCapable'].fillna(0).astype('float32')
        self.test[column] = test_df['Census_IsAlwaysOnAlwaysConnectedCapable'].fillna(0).astype('float32')

