from flask_admin import AdminIndexView, BaseView, expose, form
from flask_admin.contrib.sqla import ModelView
from flask_admin.actions import action
from flask import (current_app, session, flash, redirect, url_for,
                   request, send_from_directory)
from hashids import Hashids
from wtforms import TextAreaField
import os

from ignite.models import Markers, db


file_path = os.path.join(os.path.dirname(__file__), 'static/upload')
try:
    os.mkdir(file_path)
except OSError:
    pass

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__)))


def gen_zip(markers, in_memory=False):
    import pyqrcode
    from zipfile import ZipFile
    import io
    import os

    # This ensures that it is in the package directory rather than just cwd
    if in_memory:
        zipper_file = io.BytesIO()
        zipper = ZipFile(zipper_file, mode='w')
    else:
        zipper = ZipFile(os.path.join(__location__, 'markers.zip'), 'w')

    hashid = Hashids(min_length=6, salt=current_app.config['HASHID_KEY'])
    for i in range(0, len(markers)):
        marker = markers[i]
        marker.url = url_for('scan_marker',
                             scan_id=hashid.encode(marker.id),
                             _external=True)
        buffer = io.BytesIO()
        qrcode = pyqrcode.create(marker.url)
        qrcode.svg(buffer, scale=5, background="white")
        housename = "nohouse"
        try:
            housename = marker.house.name
        except:
            pass
        zipper.writestr(str(marker.id) + "-" +
                        marker.name + "-" +
                        housename + ".svg", buffer.getvalue())
    zipper.close()

    if in_memory:
        return zipper_file


class MyAdminIndexView(AdminIndexView):
    def is_accessible(self):
        return session.get('ad_login')

    def _handle_view(self, name, **kwargs):
        if not self.is_accessible():
            flash("You must be logged in to access this feature")
            return redirect(url_for('admin_login', next=request.url))


class QRGenView(BaseView):
    @expose('/')
    def index(self):
        return self.render('admin/index.html')

    @expose('/download', methods=['POST'])
    def download_zip(self):
        markers = Markers.query.all()
        gen_zip(markers)

        return send_from_directory(__location__,
                                   'markers.zip',
                                   as_attachment=True)


class MarkerView(ModelView):
    page_size = 50
    column_searchable_list = ['name', 'batch', 'location']
    list_template = 'admin/marker_list.html'

    @action('set_on', 'Activate',
            'Are you sure you want to activate all of these markers?')
    def action_activate(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.in_current_use = 1

            flash("Markers set to active")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('set_off', 'Deactivate',
            'Are you sure you want to set all of these makers to inactive?')
    def action_inactivate(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.in_current_use = 0

            flash("Markers set to inactive")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('hide', 'Set Hidden',
            'Are you sure you want to hide the selected markers from '
            'the torch registry page?')
    def action_hide(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.is_hidden = 1

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('show', 'Set Visible',
            'Are you sure you want to include the selected '
            'markers in the torch registry page?')
    def action_make_visble(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.is_hidden = 0

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('gencode', 'Generate QR Codes',
            'Do you want to generate QR codes for the selected '
            'markers?')
    def action_generate_codes(self, ids):
        markers = Markers.query.filter(Markers.id.in_(ids))

        gen_zip(list(markers))

        flash("Codes generated")
        return send_from_directory(__location__,
                                   'markers.zip',
                                   as_attachment=True)

    @expose('/mass')
    def mass_view(self):
        """
            Custom view for mass changing.
        """
        return self.render('admin/marker_mass.html')

    @expose('/mass/can_scan', methods=['POST'])
    def set_all_on(self):

        try:
            for marker in Markers.query.all():
                marker.in_current_use = 1

            flash("Markers set to active")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))

    @expose('/mass/no_scan',  methods=['POST'])
    def set_all_off(self):

        try:
            for marker in Markers.query.all():
                marker.in_current_use = 0

            flash("Markers set to inactive")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))

    @expose('/mass/hide', methods=['POST'])
    def set_all_hidden(self):
        try:
            for marker in Markers.query.all():
                marker.is_hidden = 1

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))

    @expose('/mass/visble', methods=['POST'])
    def set_all_visible(self):
        try:
            for marker in Markers.query.all():
                marker.is_hidden = 0

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))


class UserView(ModelView):
    column_exclude_list = ['pwhash']


class APageView(ModelView):
    form_overrides = {
        'content': TextAreaField
    }


class HouseView(ModelView):
    form_overrides = {
        'imagepath': form.FileUploadField
    }

    # Pass additional parameters to 'path' to FileUploadField constructor
    form_args = {
        'imagepath': {
            'label': 'File',
            'base_path': file_path,
            'allow_overwrite': False
        }
    }

from flask_admin import AdminIndexView, BaseView, expose, form
from flask_admin.contrib.sqla import ModelView
from flask_admin.actions import action
from flask import (current_app, session, flash, redirect, url_for,
                   request, send_from_directory)
from hashids import Hashids
from wtforms import TextAreaField
import os

from ignite.models import Markers, db


file_path = os.path.join(os.path.dirname(__file__), 'static/upload')
try:
    os.mkdir(file_path)
except OSError:
    pass

__location__ = os.path.realpath(
    os.path.join(os.getcwd(), os.path.dirname(__file__)))


def gen_zip(markers, in_memory=False):
    import pyqrcode
    from zipfile import ZipFile
    import io
    import os

    # This ensures that it is in the package directory rather than just cwd
    if in_memory:
        zipper_file = io.BytesIO()
        zipper = ZipFile(zipper_file, mode='w')
    else:
        zipper = ZipFile(os.path.join(__location__, 'markers.zip'), 'w')

    hashid = Hashids(min_length=6, salt=current_app.config['HASHID_KEY'])
    for i in range(0, len(markers)):
        marker = markers[i]
        marker.url = url_for('scan_marker',
                             scan_id=hashid.encode(marker.id),
                             _external=True)
        buffer = io.BytesIO()
        qrcode = pyqrcode.create(marker.url)
        qrcode.svg(buffer, scale=5, background="white")
        housename = "nohouse"
        try:
            housename = marker.house.name
        except:
            pass
        zipper.writestr(str(marker.id) + "-" +
                        marker.name + "-" +
                        housename + ".svg", buffer.getvalue())
    zipper.close()

    if in_memory:
        return zipper_file


class MyAdminIndexView(AdminIndexView):
    def is_accessible(self):
        return session.get('ad_login')

    def _handle_view(self, name, **kwargs):
        if not self.is_accessible():
            flash("You must be logged in to access this feature")
            return redirect(url_for('admin_login', next=request.url))


class QRGenView(BaseView):
    @expose('/')
    def index(self):
        return self.render('admin/index.html')

    @expose('/download', methods=['POST'])
    def download_zip(self):
        markers = Markers.query.all()
        gen_zip(markers)

        return send_from_directory(__location__,
                                   'markers.zip',
                                   as_attachment=True)


class MarkerView(ModelView):
    page_size = 50
    column_searchable_list = ['name', 'batch', 'location']
    list_template = 'admin/marker_list.html'

    @action('set_on', 'Activate',
            'Are you sure you want to activate all of these markers?')
    def action_activate(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.in_current_use = 1

            flash("Markers set to active")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('set_off', 'Deactivate',
            'Are you sure you want to set all of these makers to inactive?')
    def action_inactivate(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.in_current_use = 0

            flash("Markers set to inactive")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('hide', 'Set Hidden',
            'Are you sure you want to hide the selected markers from '
            'the torch registry page?')
    def action_hide(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.is_hidden = 1

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('show', 'Set Visible',
            'Are you sure you want to include the selected '
            'markers in the torch registry page?')
    def action_make_visble(self, ids):
        try:
            query = Markers.query.filter(Markers.id.in_(ids))

            for marker in query.all():
                marker.is_hidden = 0

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

    @action('gencode', 'Generate QR Codes',
            'Do you want to generate QR codes for the selected '
            'markers?')
    def action_generate_codes(self, ids):
        markers = Markers.query.filter(Markers.id.in_(ids))

        gen_zip(list(markers))

        flash("Codes generated")
        return send_from_directory(__location__,
                                   'markers.zip',
                                   as_attachment=True)

    @expose('/mass')
    def mass_view(self):
        """
            Custom view for mass changing.
        """
        return self.render('admin/marker_mass.html')

    @expose('/mass/can_scan', methods=['POST'])
    def set_all_on(self):

        try:
            for marker in Markers.query.all():
                marker.in_current_use = 1

            flash("Markers set to active")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))

    @expose('/mass/no_scan',  methods=['POST'])
    def set_all_off(self):

        try:
            for marker in Markers.query.all():
                marker.in_current_use = 0

            flash("Markers set to inactive")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))

    @expose('/mass/hide', methods=['POST'])
    def set_all_hidden(self):
        try:
            for marker in Markers.query.all():
                marker.is_hidden = 1

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))

    @expose('/mass/visble', methods=['POST'])
    def set_all_visible(self):
        try:
            for marker in Markers.query.all():
                marker.is_hidden = 0

            flash("Markers set to hidden")
            db.session.commit()
        except Exception as ex:
            if not self.handle_view_exception(ex):
                raise
            print(ex)
            flash("Failed to update database")

        return redirect(url_for('.mass_view'))


class UserView(ModelView):
    column_exclude_list = ['pwhash']


class APageView(ModelView):
    form_overrides = {
        'content': TextAreaField
    }


class HouseView(ModelView):
    form_overrides = {
        'imagepath': form.FileUploadField
    }

    # Pass additional parameters to 'path' to FileUploadField constructor
    form_args = {
        'imagepath': {
            'label': 'File',
            'base_path': file_path,
            'allow_overwrite': False
        }
    }

# This ensures that it is in the package directory rather than just cwd Custom view for mass changing. # Pass additional parameters to 'path' to FileUploadField constructor