#!/usr/bin/env python

# RaidGuessFS, a FUSE pseudo-filesystem to guess RAID parameters of a damaged device
# Copyright (C) 2015 Ludovic Pouzenc <ludovic@pouzenc.fr>
#
# This file is part of RaidGuessFS.
#
# RaidGuessFS is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# RaidGuessFS is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with RaidGuessFS. If not, see <http://www.gnu.org/licenses/>

import multiprocessing, binascii, logging
import mydisks

def do_find_files(d,state):
    logging.info("Enter do_find_files()")
    try:
        state['TODO'] = 'Not yet implemented'
        state['progress'] = 100
    except Exception as e:
        logging.exception(e)
    logging.info("Exit. do_find_files()")


def do_find_bootsect(d,state):
    logging.info("Enter do_find_bootsect()")
    try:
        ref_sig = binascii.unhexlify('55AA')

        start = 0
        end = min(d.disks_size)
        one_percent = (end - start) / 100
        one_percent = one_percent + ( (-one_percent)%512 )
        logging.debug("start/end/1pc : %i / %i / %i"%(start,end,one_percent))

        state['found'] = []
        state['progress'] = 0
        for offset in range(start, end, 512):
            for disk_no in range(d.disk_count):
                d.disks[disk_no].seek(offset)
                data = d.disks[disk_no].read(512)
                sig = data[510:]
                if sig == ref_sig:
                    f = state['found']
                    if len(f) < 200:
                        f.append((disk_no,offset))
                        state['found'] = f
                    else:
                        raise Exception('Aborting after too many matches')

            if offset % one_percent == 0:
                state['progress'] = state['progress'] + 1
        state['progress'] = 100
    except Exception as e:
        logging.exception(e)
    logging.info("Exit. do_find_bootsect()")



class MyTasks():
    """Auxiliary class, managing long or background tasks"""

    TASK_NAMES = [ 'find_bootsect', 'find_files' ]

    def __init__(self, mydisks):
        self.tasks = []
        self.d = mydisks
        self.find_files_pathlist = []
        m = multiprocessing.Manager()
        self.find_bootsect_state = m.dict()
        self.find_bootsect_process = None
        self.find_files_state = m.dict()
        self.find_files_process = None

    def get_find_files_pathlist(self):
        return self.find_files_pathlist

    def get_find_files_pathlist_str(self):
        return '\n'.join(self.find_files_pathlist)

    def task_start(self, task_name):
        if task_name == 'find_files':
            self.find_files_process = multiprocessing.Process(
                    target = do_find_files,
                    args = (self.d, self.find_files_state)
            )
            self.find_files_process.start()
        elif task_name == 'find_bootsect':
            self.find_bootsect_process = multiprocessing.Process(
                    target = do_find_bootsect,
                    args = (self.d, self.find_bootsect_state)
            )
            self.find_bootsect_process.start()
        else:
            raise ValueError('Valid task names are : %s'%','.join(MyTasks.TASK_NAMES))
    
    def task_kill(self, task_name):
        if task_name == 'find_bootsect':
            if self.find_bootsect_process != None and self.find_bootsect_process.is_alive():
                self.find_bootsect_process.terminate()
        elif task_name == 'find_files':
            if self.find_files_process != None and self.find_files_process.is_alive():
                self.find_files_process.terminate()
        else:
            raise ValueError('Valid task names are : %s'%','.join(MyTasks.TASK_NAMES))

    def set_find_files_pathlist(self, new_find_files_pathlist):
        self.find_files_pathlist = new_find_files_pathlist

    def read_find_bootsect(self):
        if self.find_bootsect_process == None:
            return 'This task has never been started\n'
        else:
            return '%s\n'%self.find_bootsect_state

    def read_find_files(self):
        if self.find_files_process == None:
            return 'This task has never been started\n'
        else:
            return '%s\n'%self.find_files_state