################################################################################
#                                                                              #
#                This file is part of the Buildbotics firmware.                #
#                                                                              #
#                  Copyright (c) 2015 - 2018, Buildbotics LLC                  #
#                             All rights reserved.                             #
#                                                                              #
#     This file ("the software") is free software: you can redistribute it     #
#     and/or modify it under the terms of the GNU General Public License,      #
#      version 2 as published by the Free Software Foundation. You should      #
#      have received a copy of the GNU General Public License, version 2       #
#     along with the software. If not, see <http://www.gnu.org/licenses/>.     #
#                                                                              #
#     The software 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       #
#               Lesser General Public License for more details.                #
#                                                                              #
#       You should have received a copy of the GNU Lesser General Public       #
#                License along with the software.  If not, see                 #
#                       <http://www.gnu.org/licenses/>.                        #
#                                                                              #
#                For information regarding this software email:                #
#                  "Joseph Coffland" <joseph@buildbotics.com>                  #
#                                                                              #
################################################################################

import os
import stat
import shutil
import json
import bbctrl
from datetime import datetime
from tornado import gen
from tornado.web import HTTPError


def clean_path(path):
    if path is None: return ''

    path = os.path.normpath(path)
    if path.startswith('..'): raise HTTPError(400, 'Invalid path')
    return '/' + path.lstrip('./')


def timestamp_to_iso8601(ts):
    return datetime.fromtimestamp(ts).replace(microsecond = 0).isoformat() + 'Z'


def get_drives():
    # TODO report real space
    # List USB drives
    return [dict(name = 'root', space = 0)]


class FileSystemHandler(bbctrl.RequestHandler):
    def get_log(self, name = 'FileSystemHandler'):
        return super().get_log(name)


    def ensure_dir(self, path):
        realpath = self.get_upload() + path
        if not os.path.exists(realpath):
            os.makedirs(realpath)
            self.emit('fs-mkdir', path)


    def delete(self, path):
        path = clean_path(path)
        realpath = self.get_upload() + path

        try:
            if os.path.isdir(realpath): shutil.rmtree(realpath, True)
            else: os.unlink(realpath)
        except OSError: pass

        self.emit('fs-delete', path)
        self.get_log().info('Deleted ' + path)


    def put(self, path):
        path = clean_path(path)

        if 'file' in self.request.files:
            self.ensure_dir(os.path.dirname(path))
            file = self.request.files['file'][0]
            realpath = self.get_upload() + path

            with open(realpath.encode('utf8'), 'wb') as f:
                f.write(file['body'])

            self.emit('fs-write', path)
            self.get_log().info('Wrote ' + path)

        else: self.ensure_dir(path)

        os.sync()


    @gen.coroutine
    def get(self, path):
        path = clean_path(path)
        realpath = self.get_upload() + path

        if not os.path.exists(realpath): raise HTTPError(404, 'File not found')
        elif os.path.isdir(realpath):
            l = []

            if os.path.exists(realpath):
                for name in os.listdir(realpath):
                    s = os.stat(realpath + '/' + name)

                    d = dict(name = name)
                    d['created'] = timestamp_to_iso8601(s.st_ctime)
                    d['modified'] = timestamp_to_iso8601(s.st_mtime)
                    d['size']  = s.st_size
                    d['dir']   = stat.S_ISDIR(s.st_mode)

                    l.append(d)

            d = dict(
                path = path, drive = 'root', drives = get_drives(), dir = l)

            self.set_header('Content-Type', 'application/json')
            self.write(json.dumps(d, separators = (',', ':')))

        else:
            with open(realpath, 'r') as f:
                self.write(f.read())
