import re

from ceph_volume.util.disk import human_readable_size
from ceph_volume import process
from ceph_volume import sys_info

report_template = """
/dev/{geomname:<16} {mediasize:<16} {rotational!s:<7} {descr}"""
# {geomname:<25} {mediasize:<12} {rotational!s:<7} {mode!s:<9} {descr}"""

def geom_disk_parser(block):
    """
    Parses lines in 'geom disk list` output.

    Geom name: ada3
    Providers:
    1. Name: ada3
       Mediasize: 40018599936 (37G)
       Sectorsize: 512
       Stripesize: 4096
       Stripeoffset: 0
       Mode: r2w2e4
       descr: Corsair CSSD-F40GB2
       lunid: 5000000000000236
       ident: 111465010000101800EC
       rotationrate: 0
       fwsectors: 63
       fwheads: 16

    :param line: A string, with the full block for `geom disk list`
    """
    pairs = block.split(';')
    parsed = {}
    for pair in pairs:
        if 'Providers' in pair:
            continue
        try:
            column, value = pair.split(':')
        except ValueError:
            continue
        # fixup
        column = re.sub("\s+", "", column)
        column= re.sub("^[0-9]+\.", "", column)
        value = value.strip()
        value = re.sub('\([0-9A-Z]+\)', '', value)
        parsed[column.lower()] = value
    return parsed

def get_disk(diskname):
    """
    Captures all available info from geom
    along with interesting metadata like sectors, size, vendor,
    solid/rotational, etc...

    Returns a dictionary, with all the geom fields as keys.
    """

    command = ['/sbin/geom', 'disk', 'list', re.sub('/dev/', '', diskname)]
    out, err, rc = process.call(command)
    geom_block = ""
    for line in out:
        line.strip()
        geom_block += ";" + line
    disk = geom_disk_parser(geom_block)
    return disk

def get_disks():
    command = ['/sbin/geom', 'disk', 'status', '-s']
    out, err, rc = process.call(command)
    disks = {}
    for path in out:
        dsk, rest1, rest2 = path.split()
        disk = get_disk(dsk)
        disks['/dev/'+dsk] = disk
    return disks

class Disks(object):

    def __init__(self, path=None):
        if not sys_info.devices:
            sys_info.devices = get_disks()
        self.disks = {}
        for k in sys_info.devices:
            if path != None:
                if path in k:
                    self.disks[k] = Disk(k)
            else:
                self.disks[k] = Disk(k)

    def pretty_report(self, all=True):
        output = [
            report_template.format(
                geomname='Device Path',
                mediasize='Size',
                rotational='rotates',
                descr='Model name',
                mode='available',
            )]
        for disk in sorted(self.disks):
            output.append(self.disks[disk].report())
        return ''.join(output)

    def json_report(self):
        output = []
        for disk in sorted(self.disks):
            output.append(self.disks[disk].json_report())
        return output


class Disk(object):

    report_fields = [
        'rejected_reasons',
        'available',
        'path',
        'sys_api',
    ]
    pretty_report_sys_fields = [
        'human_readable_size',
        'model',
        'removable',
        'ro',
        'rotational',
        'sas_address',
        'scheduler_mode',
        'vendor',
    ]

    def __init__(self, path):
        self.abspath = path
        self.path = path
        self.reject_reasons = []
        self.available = True
        self.sys_api = sys_info.devices.get(path)

    def report(self):
        return report_template.format(
            geomname=self.sys_api.get('geomname'),
            mediasize=human_readable_size(int(self.sys_api.get('mediasize'))),
            rotational=int(self.sys_api.get('rotationrate')) != 0,
            mode=self.sys_api.get('mode'),
            descr=self.sys_api.get('descr')
        )

    def json_report(self):
        output = {k.strip('_'): v for k, v in vars(self).items()}
        return output

