
class EngineeringNumberConverter():

    prefixes = [
        ('y', 1e-24),
        ('z', 1e-21),
        ('a', 1e-18),
        ('f', 1e-15),
        ('p', 1e-12),
        ('n', 1e-9),
        ('u', 1e-6),
        ('m', 1e-3),
        # We skip centi and dezi because no one really uses these besides for length measurements
        ('', 1),
        # We also skip h for hekto
        ('k', 1e3),
        ('M', 1e6),
        ('G', 1e9),
        ('T', 1e12),
        ('P', 1e15),
        ('E', 1e18),
        ('Z', 1e21),
        ('Y', 1e24),
    ]
    it_prefixes = [
        ('', 1),
        ('Ki', 1024),
        ('Mi', 1024*1024),
        ('Gi', 1024*1024*1024),
        ('Ti', 1024*1024*1024*1024)
    ]
    
    @classmethod
    def number_to_engineering(c, number, it_unit = False):
        """
        Convert a number to engineering SI syntax with prefix.
        This function will return a tuple of (new_number, prefix)
        """
        if it_unit:
            used_prefixes = c.it_prefixes
        else:
            used_prefixes = c.prefixes

        if (len(used_prefixes) < 2):
            return (number / used_prefixes[0][1], used_prefixes[0])
        
        for i, (prefix, scale) in enumerate(used_prefixes[1:], 1):
            if number < scale:
                return (number / used_prefixes[i-1][1], used_prefixes[i-1][0])
        
        return (number / used_prefixes[-1][1], used_prefixes[-1][0])

    @classmethod
    def engineering_to_number(c, input):
        cleaned_input = input.strip().replace(' ', '')

        selected_scaling = 1

        for (prefix, scale) in c.prefixes+c.it_prefixes:
            if prefix == '':
                continue
            if cleaned_input.endswith(prefix):
                cleaned_input = cleaned_input.replace(prefix, '')
                selected_scaling = scale
                break
        
        return float(cleaned_input) * selected_scaling