#
#  Epour - A bittorrent client using EFL and libtorrent
#
#  Copyright 2012-2017 Kai Huuhko <kai.huuhko@gmail.com>
#
#  This program 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.
#
#  This program 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 this program; if not, write to the Free Software
#  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#  MA 02110-1301, USA.
#

import os
import sys
import cgi
import logging
from datetime import timedelta, datetime
import gettext
try:
    gettext.install("epour", unicode=True)
except Exception:
    gettext.install("epour")

import libtorrent as lt

from efl.evas import EVAS_HINT_EXPAND, EVAS_HINT_FILL, \
    EVAS_ASPECT_CONTROL_VERTICAL, Rectangle
from efl.ecore import Timer
from efl import elementary as elm
from efl.elementary import Genlist, GenlistItemClass, \
    ELM_GENLIST_ITEM_FIELD_TEXT, ELM_GENLIST_ITEM_FIELD_CONTENT, \
    ELM_OBJECT_SELECT_MODE_NONE, ELM_OBJECT_SELECT_MODE_DEFAULT, \
    ELM_LIST_COMPRESS
from efl.elementary import Window, Background, ELM_WIN_BASIC
from efl.elementary import Icon, Image
from efl.elementary import Box
from efl.elementary import Label
from efl.elementary import Panel, ELM_PANEL_ORIENT_BOTTOM
from efl.elementary import Table
from efl.elementary import Menu
from efl.elementary import Configuration
from efl.elementary import Toolbar, ELM_TOOLBAR_SHRINK_NONE
from efl.elementary import Theme
from efl.elementary import Progressbar

from xdg.BaseDirectory import load_data_paths

from .Widgets import ConfirmExit, Error, Information, BlockGraph

from .intrepr import intrepr

EXPAND_BOTH = EVAS_HINT_EXPAND, EVAS_HINT_EXPAND
EXPAND_HORIZ = EVAS_HINT_EXPAND, 0.0
FILL_BOTH = EVAS_HINT_FILL, EVAS_HINT_FILL
FILL_HORIZ = EVAS_HINT_FILL, 0.5

elm_conf = Configuration()
scale = elm_conf.scale

log = logging.getLogger("epour.gui")

theme_file = None

for data_path in load_data_paths("epour"):
    if os.path.exists(data_path):
        if os.path.exists(os.path.join(data_path, "themes", "default.edj")):
            theme_file = os.path.join(data_path, "themes", "default.edj")
            break

if not theme_file:
    dir_path = os.getcwd()
    path = os.path.join(dir_path, "data", "themes", "default.edj")

    if os.path.exists(path):
        theme_file = path
    else:
        sys.exit("Theme file not found, will not progress without it. Compile the theme with setup.py build_edc")


class MainInterface(object):

    def __init__(self, parent, session):
        self._session = session
        self.itc = TorrentClass(self._session, "torrent")

        self.torrentitems = {}

        theme = Theme.default_get()
        theme.overlay_add(theme_file)

        win = self.win = Window(
            "epour", ELM_WIN_BASIC, size=(480 * scale, 400 * scale),
            screen_constrain=True)
        win.title = "Epour"
        win.callback_delete_request_add(lambda x: self.quit())

        bg = Background(win, size_hint_weight=EXPAND_BOTH, color=(0, 0, 0))
        win.resize_object_add(bg)
        bg.show()

        mbox = Box(win, size_hint_weight=EXPAND_BOTH)
        win.resize_object_add(mbox)
        mbox.show()

        # --- TOOLBAR ---
        tb = Toolbar(
            win, size_hint_align=FILL_HORIZ, homogeneous=False,
            shrink_mode=ELM_TOOLBAR_SHRINK_NONE,
            select_mode=ELM_OBJECT_SELECT_MODE_NONE)
        tb.menu_parent = win

        item = tb.item_append(
            "toolbar-new", _("Add torrent"),
            lambda x, y: self.add_torrent())

        def pause_session(it):
            self._session.pause()
            it.state_set(it.state_next())

        def resume_session(it):
            session.resume()
            del it.state

        item = tb.item_append(
            "session-pause", _("Pause Session"),
            lambda tb, it: pause_session(it))
        item.state_add(
            "session-resume", _("Resume Session"),
            lambda tb, it: resume_session(it))

        def prefs_general_cb():
            from .Preferences import PreferencesGeneral
            PreferencesGeneral(self, self._session).show()

        def prefs_proxy_cb():
            from .Preferences import PreferencesProxy
            PreferencesProxy(self, self._session).show()

        def prefs_session_cb():
            from .Preferences import PreferencesSession
            PreferencesSession(self, self._session).show()

        item = tb.item_append("toolbar-settings", _("Preferences"))
        item.menu = True
        item.menu.item_add(
            None, _("General"), "toolbar-settings",
            lambda o, i: prefs_general_cb())
        item.menu.item_add(
            None, _("Proxy"), "toolbar-settings",
            lambda o, i: prefs_proxy_cb())
        item.menu.item_add(
            None, _("Session"), "toolbar-settings",
            lambda o, i: prefs_session_cb())

        item = tb.item_append("toolbar-quit", _("Exit"),
                              lambda tb, it: self.quit())

        mbox.pack_start(tb)
        tb.show()

        # --- TORRENT LIST ---
        self.tlist = tlist = Genlist(
            mbox, select_mode=ELM_OBJECT_SELECT_MODE_DEFAULT,
            mode=ELM_LIST_COMPRESS, size_hint_weight=EXPAND_BOTH,
            size_hint_align=FILL_BOTH, homogeneous=True)

        def item_activated_cb(gl, item):
            torrent = item.data
            handle = torrent.handle
            itm = ItemMenu(tlist, item, self._session, handle)
            itm.focus = True

        tlist.callback_activated_add(item_activated_cb)
        tlist.callback_clicked_right_add(item_activated_cb)
        tlist.show()

        mbox.pack_end(tlist)

        topbox = Box(win, size_hint_weight=EXPAND_BOTH, horizontal=False)

        pad1 = Rectangle(win.evas, size_hint_weight=EXPAND_BOTH)

        p = Panel(
            topbox, size_hint_weight=EXPAND_BOTH, size_hint_align=FILL_BOTH,
            color=(200, 200, 200, 200), orient=ELM_PANEL_ORIENT_BOTTOM)

        p.content = SessionStatus(win, session)
        p.hidden = True
        p.show()

        win.resize_object_add(topbox)

        topbox.pack_end(pad1)
        topbox.pack_end(p)
        topbox.stack_above(mbox)
        topbox.show()

        def _add_torrent_cb(a):
            e = a.error
            if e.value() > 0:
                return
            h = a.handle
            info_hash = h.info_hash()
            torrent = session.torrents[str(info_hash)]
            self.add_torrent_item(torrent)

        def _torrent_removed_cb(a):
            self.remove_torrent_item(str(a.info_hash))

        session.alert_manager.callback_add(
            "add_torrent_alert", _add_torrent_cb)
        session.alert_manager.callback_add(
            "torrent_removed_alert", _torrent_removed_cb)

        def torrent_paused_resumed_cb(a):
            h = a.handle
            if not h.is_valid():
                log.debug("Paused state changed for invalid handle.")
                return

            info_hash = str(h.info_hash())
            if info_hash not in self.torrentitems:
                log.debug("Paused state for %s changed but not in list of gui items", str(info_hash))
                return

            torrent = self._session.torrents[info_hash]
            torrent.status = h.status(0)

            self.torrentitems[info_hash].fields_update(
                "elm.swallow.icon", ELM_GENLIST_ITEM_FIELD_CONTENT
            )

        for a_name in "torrent_paused_alert", "torrent_resumed_alert":
            session.alert_manager.callback_add(a_name, torrent_paused_resumed_cb)

        def state_changed_cb(a):
            h = a.handle
            if not h.is_valid():
                log.debug("State changed for invalid handle.")
                return

            info_hash = str(h.info_hash())
            if info_hash not in self.torrentitems:
                log.debug("%s state changed but not in list", str(info_hash))
                return

            torrent = self._session.torrents[info_hash]
            torrent.state = a.state

            self.torrentitems[info_hash].fields_update(
                "elm.swallow.icon", ELM_GENLIST_ITEM_FIELD_CONTENT
            )

        session.alert_manager.callback_add(
            "state_changed_alert", state_changed_cb)

        def state_update_alert_cb(a):
            statuses = a.status
            for status in statuses:
                info_hash = str(status.info_hash)

                if info_hash not in self.torrentitems:
                    return

                item = self.torrentitems[info_hash]

                item.fields_update(
                    "*", ELM_GENLIST_ITEM_FIELD_TEXT
                )
                item.fields_update(
                    "elm.swallow.progress", ELM_GENLIST_ITEM_FIELD_CONTENT
                )

        session.alert_manager.callback_add(
            "state_update_alert", state_update_alert_cb)

        def torrent_finished_cb(a):
            msg = _("Torrent {} has finished downloading.").format(
                cgi.escape(a.handle.name())
            )
            log.info(msg)

            Information(self.win, msg)

        Timer(15.0, lambda: session.alert_manager.callback_add(
            "torrent_finished_alert", torrent_finished_cb))

    def add_torrent(self, t_uri=None):
        from .TorrentSelector import TorrentSelector
        TorrentSelector(self.win, self._session, t_uri)

    def run_mainloop(self):
        self.win.show()

        # self.timer = Timer(1.0, self.update)
        # self.win.on_del_add(lambda x: self.timer.delete())
        # self.win.callback_withdrawn_add(lambda x: self.timer.freeze())
        # self.win.callback_iconified_add(lambda x: self.timer.freeze())
        # self.win.callback_normal_add(lambda x: self.timer.thaw())
        elm.run()

    def stop_mainloop(self):
        elm.exit()

    def update(self):
        #log.debug("Torrent list TICK")
        # for v in self.tlist.realized_items_get():
        #     v.fields_update("*", ELM_GENLIST_ITEM_FIELD_TEXT)
        return True

    def _torrent_item_tooltip_cb(self, gl, it, tooltip, session, torrent):
        return TorrentTooltip(tooltip, session, torrent)

    def add_torrent_item(self, torrent):
        info_hash = torrent.info_hash

        item = self.tlist.item_append(self.itc, torrent)
        item.tooltip_content_cb_set(self._torrent_item_tooltip_cb, self._session, torrent)
        item.tooltip_window_mode_set(True)
        self.torrentitems[str(info_hash)] = item

    def remove_torrent_item(self, info_hash):
        it = self.torrentitems.pop(info_hash, None)
        if it is not None:
            it.delete()

    def show_error(self, title, text):
        Error(self.win, title, text)

    def quit(self, *args):
        if self._session.conf.getboolean("Settings", "confirm_exit"):
            ConfirmExit(self.win, self._quit_cb)
        else:
            self._quit_cb()

    def _quit_cb(self):
        self.win.hide()
        self._session.shutdown()


class SessionStatus(Table):

    log = logging.getLogger("epour.gui.session")

    def __init__(self, parent, session):
        Table.__init__(self, parent)
        self._session = session

        s = session.status()

        self.homogeneous = True
        self.padding = 5, 2

        ses_pause_ic = self.ses_pause_ic = Icon(parent)
        ses_pause_ic.size_hint_align = -1.0, -1.0

        if session.is_paused():
            try:
                ses_pause_ic.standard = "player_pause"
            except Exception:
                try:
                    ses_pause_ic.standard = "media-playback-pause"
                except Exception:
                    log.warn("the pause icon could not be set")
        else:
            try:
                ses_pause_ic.standard = "player_play"
            except Exception:
                try:
                    ses_pause_ic.standard = "media-playback-play"
                except Exception:
                    log.warn("the play icon could not be set")

        self.pack(ses_pause_ic, 1, 0, 1, 1)
        ses_pause_ic.show()

        t = _("Session")
        title_l = Label(parent, text="<b>%s</b>" % t)
        self.pack(title_l, 0, 0, 1, 1)
        title_l.show()

        d_ic = Icon(parent, size_hint_align=FILL_BOTH)
        try:
            d_ic.standard = "down"
        except Exception:
            log.debug("Setting d_ic failed")
        self.pack(d_ic, 0, 1, 1, 1)
        d_ic.show()

        d_l = self.d_l = Label(parent)
        d_l.text = "{}/s".format(intrepr(s.payload_download_rate))
        self.pack(d_l, 1, 1, 1, 1)
        d_l.show()

        u_ic = Icon(self, size_hint_align=FILL_BOTH)
        try:
            u_ic.standard = "up"
        except Exception:
            log.debug("Setting u_ic failed")
        self.pack(u_ic, 0, 2, 1, 1)
        u_ic.show()

        u_l = self.u_l = Label(parent)
        u_l.text = "{}/s".format(intrepr(s.payload_upload_rate))
        self.pack(u_l, 1, 2, 1, 1)
        u_l.show()

        peer_t = Label(parent, text=_("Peer connections"))
        self.pack(peer_t, 0, 3, 1, 1)
        peer_t.show()

        peer_l = self.peer_l = Label(parent, text=str(s.num_peers))
        self.pack(peer_l, 1, 3, 1, 1)
        peer_l.show()

        uploads_t = Label(parent, text=_("Upload slots"))
        self.pack(uploads_t, 0, 4, 1, 1)
        uploads_t.show()

        t = "%s/%s" % (str(s.num_unchoked), str(s.allowed_upload_slots))
        uploads_l = self.uploads_l = Label(parent, text=t)
        self.pack(uploads_l, 1, 4, 1, 1)
        uploads_l.show()

        listen_t = Label(parent, text=_("Listening"))
        self.pack(listen_t, 0, 5, 1, 1)
        listen_t.show()

        listen_l = self.listen_l = Label(
            parent, text=str(session.is_listening()))
        self.pack(listen_l, 1, 5, 1, 1)
        listen_l.show()

        self.show()

        self.update_timer = Timer(1.0, self.update)
        self.on_del_add(lambda x: self.update_timer.delete())
        self.top_widget.callback_withdrawn_add(
            lambda x: self.update_timer.freeze())
        self.top_widget.callback_iconified_add(
            lambda x: self.update_timer.freeze())
        self.top_widget.callback_normal_add(lambda x: self.update_timer.thaw())

    def update(self):
        #log.debug("Session status TICK")
        s = self._session.status()

        self.d_l.text = "{}/s".format(intrepr(s.payload_download_rate))
        self.u_l.text = "{}/s".format(intrepr(s.payload_upload_rate))
        self.peer_l.text = str(s.num_peers)

        t = "%s/%s" % (str(s.num_unchoked), str(s.allowed_upload_slots))
        self.uploads_l.text = t

        self.listen_l.text = str(self._session.is_listening())

        icon = "media-playback-pause" if self._session.is_paused() else "media-playback-play"
        try:
            self.ses_pause_ic.standard = icon
        except Exception:
            pass

        return True


class TorrentClass(GenlistItemClass):

    state_str = (
        _('Queued'), _('Checking'), _('Downloading metadata'),
        _('Downloading'), _('Finished'), _('Seeding'), _('Allocating'),
        _('Checking resume data'))

    state_ic = (
        "torrent-queued", "torrent-checking-files",
        "torrent-downloading-metadata", "torrent-downloading",
        "torrent-finished", "torrent-seeding", "torrent-allocating",
        "torrent-checking-resume-data")

    log = logging.getLogger("epour.gui.torrent_list")

    def __init__(self, session, *args, **kwargs):
        GenlistItemClass.__init__(self, *args, **kwargs)

        self._session = session

    def text_get(self, obj, part, item_data):
        torrent = item_data
        handle = torrent.handle

        if not handle.is_valid():
            return _("Invalid torrent")

        if part == "elm.text":
            return '%s' % (torrent.status.name)
        elif part == "elm.text.sub":
            status = torrent.status
            qp = status.queue_position
            if qp == -1:
                qp = "seeding"

            string = ""

            eta = self.get_eta(status)

            if eta:
                # NOTE: Estimated Time of Arrival (time until the process is finished)
                string += _("ETA: {0} ").format(timedelta(seconds=eta))

            if not status.is_seeding:
                string += _("Download: {0}/s ").format(intrepr(status.download_payload_rate, precision=0))

            string += _("Upload: {0}/s ").format(intrepr(status.upload_payload_rate, precision=0))

            string += _("Queue position: {0}").format(qp)

            return string

    def reusable_content_get(self, obj, part, item_data, old_content):
        if part == "elm.swallow.icon":
            torrent = item_data
            handle = torrent.handle

            if not handle.is_valid():
                return

            state = torrent.state
            if old_content:
                ic = old_content
            else:
                ic = Image(obj)
            group = "states/" + self.state_ic[state]
            ic.file_set(theme_file, group)
            ic.tooltip_text_set(self.state_str[state])
            ic.size_hint_aspect_set(EVAS_ASPECT_CONTROL_VERTICAL, 1, 1)
            return ic
        elif part == "elm.swallow.end":
            torrent = item_data
            handle = torrent.handle

            if not handle.is_valid():
                return

            status = torrent.status
            if old_content:
                ic = old_content
            else:
                ic = Image(obj)
            group = "states/"
            if status.paused:
                group += "torrent-paused"
            else:
                group += "torrent-active"
            ic.file_set(theme_file, group)
            return ic
        else:
            torrent = item_data
            handle = torrent.handle

            if not handle.is_valid():
                return
            status = torrent.status
            if old_content:
                pb = old_content
            else:
                pb = Progressbar(obj)
                pb.style = "simple"
                pb.unit_format = None
            pb.value = status.progress
            return pb

    def get_eta(self, s):
        # if s.is_seeding and self.options["stop_at_ratio"]:
        #     # We're a seed, so calculate the time to the 'stop_share_ratio'
        #     if not s.upload_payload_rate:
        #         return 0
        #     stop_ratio = self._session.settings().share_ratio_limit
        #     return (
        #         (s.all_time_download * stop_ratio) -
        #         s.all_time_upload
        #         ) / s.upload_payload_rate

        if s.download_payload_rate == 0:
            return 0

        left = s.total_wanted - s.total_wanted_done

        if left <= 0:
            return 0

        eta = int(round(left / s.download_payload_rate))

        return eta


class ItemMenu(Menu):

    def __init__(self, parent, item, session, h):
        Menu.__init__(self, parent)

        self.item_add(
            None,
            _("Resume") if h.is_paused() else _("Pause"),
            None,
            self.resume_torrent_cb if h.is_paused() else self.pause_torrent_cb,
            h
        )
        q = self.item_add(None, _("Queue"), None, None)
        self.item_add(
            q, _("Up"), None, lambda x, y: h.queue_position_up())
        self.item_add(
            q, _("Down"), None, lambda x, y: h.queue_position_down())
        self.item_add(
            q, _("Top"), None, lambda x, y: h.queue_position_top())
        self.item_add(
            q, _("Bottom"), None, lambda x, y: h.queue_position_bottom())
        rem = self.item_add(
            None, _("Remove torrent"), None,
            self.remove_torrent_cb, item, session, h, False)
        self.item_add(
            rem, _("and data files"), None,
            self.remove_torrent_cb, item, session, h, True)
        self.item_separator_add(None)
        it = self.item_add(
            None, _("Force reannounce"), None, lambda x, y: h.force_reannounce())
        it.tooltip_text_set(
            "<b>Force reannounce</b> will force this torrent<br>"
            "to do another tracker request, to receive new<br>"
            "peers.<br><br>"
            "If the tracker's min_interval has not passed<br>"
            "since the last announce, the forced announce<br>"
            "will be scheduled to happen immediately as<br>"
            "the min_interval expires. This is to honor<br>"
            "trackers minimum re-announce interval settings.")
        self.item_add(
            None, _("Force DHT reannounce"), None,
            lambda x, y: h.force_dht_announce())
        it = self.item_add(
            None, _("Scrape tracker"), None,
            lambda x, y: h.scrape_tracker())
        it.tooltip_text_set(
            "<b>Scrape tracker</b> will send a scrape request to the<br>"
            "tracker. A scrape request queries the tracker for<br>"
            "statistics such as total number of incomplete peers,<br>"
            "complete peers, number of downloads etc.")
        it = self.item_add(
            None, _("Force re-check"), None,
            lambda x, y: h.force_recheck())
        it.tooltip_text_set(
            "force_recheck puts the torrent back in a state<br>"
            "where it assumes to have no resume data.<br>"
            "All peers will be disconnected and the torrent<br>"
            "will stop announcing to the tracker. The torrent<br>"
            "will be added to the checking queue, and will be<br>"
            "checked (all the files will be read and compared<br>"
            "to the piece hashes).<br>"
            "Once the check is complete, the torrent will start<br>"
            "connecting to peers again, as normal.")
        self.item_separator_add(None)
        it = self.item_add(
            None, _("Torrent properties"), None,
            self.torrent_props_cb, h)

        def files_cb(menu, it, h):
            from .TorrentProps import TorrentFiles
            TorrentFiles(self.top_widget, h)
        self.item_add(
            it, "Files", None,
            files_cb, h)

        self.move(*item.track_object.pos)
        del item.track_object

        self.show()

    def remove_torrent_cb(self, menu, item, glitem, session, h, with_data=False):
        menu.close()
        session.remove_torrent(h, with_data)

    def resume_torrent_cb(self, menu, item, h):
        h.resume()
        h.auto_managed(True)

    def pause_torrent_cb(self, menu, item, h):
        h.auto_managed(False)
        h.pause(flags=lt.pause_flags_t.graceful_pause)

    def torrent_props_cb(self, menu, item, h):
        menu.close()
        from .TorrentProps import TorrentProps
        TorrentProps(self.top_widget, h).show()


class TorrentTooltip(Table):

    items = (
        (_("Time when added"), datetime.fromtimestamp, "added_time"),
        (_("Time when completed"), datetime.fromtimestamp, "completed_time"),
        (_("All time downloaded"), intrepr, "all_time_download"),
        (_("All time uploaded"), intrepr, "all_time_upload"),
        (_("Total wanted done"), intrepr, "total_wanted_done"),
        (_("Total wanted"), intrepr, "total_wanted"),
        (_("Total downloaded this session"),
            intrepr, "total_payload_download"),
        (_("Total uploaded this session"), intrepr, "total_payload_upload"),
        (_("Total failed"), intrepr, "total_failed_bytes"),
        (_("Number of seeds"), None, "num_seeds"),
        (_("Number of peers"), None, "num_peers"))

    bold = "font_weight=Bold"

    def __init__(self, parent, session, torrent):

        handle = torrent.handle

        if not handle.is_valid():
            raise ValueError("Invalid handle")

        flags = lt.status_flags_t.query_pieces
        status = handle.status(flags)

        Table.__init__(self, parent, size_hint_weight=EXPAND_BOTH)

        value_labels = []

        for i, (desc, conv, attr_name) in enumerate(self.items):
            desc = "<font %s>%s</>" % (self.bold, desc)
            l1 = Label(self, text=desc)
            l1.show()
            self.pack(l1, 0, i, 1, 1)
            v = getattr(status, attr_name)
            if conv:
                if conv == datetime.fromtimestamp and v == 0:
                    v = _("N/A")
                else:
                    v = conv(v)
            l2 = Label(self, text=str(v))
            value_labels.append(l2)
            l2.show()
            self.pack(l2, 1, i, 1, 1)

        i += 1

        l = Label(self)
        self.pack(l, 0, i, 1, 1)
        l.show()

        WIDTH = 30
        HEIGHT = 4

        graph = BlockGraph(
            self, status.pieces, status.num_pieces,
            size=(WIDTH, HEIGHT), size_hint_align=FILL_BOTH)

        l.text = "".join((
            "<font %s>" % (self.bold),
            _("Pieces (scaled 1:%d)") % (graph.block_size),
            "</>"))

        self.pack(graph, 1, i, 1, 1)
        graph.show()

        self.timer = Timer(1.0, self.update, torrent, self.items, value_labels, graph)
        self.on_del_add(lambda x: self.timer.delete())

    @staticmethod
    def update(torrent, items, value_labels, g):
        #log.debug("Tooltip TICK")
        handle = torrent.handle
        flags = lt.status_flags_t.query_pieces
        s = handle.status(flags)
        for i, l in enumerate(value_labels):
            conv, attr_name = items[i][1:]
            v = getattr(s, attr_name)
            if conv:
                if conv == datetime.fromtimestamp and v == 0:
                    v = _("N/A")
                else:
                    v = conv(v)
            l.text = str(v)

        if s.has_metadata:
            g.update(s.pieces, s.num_pieces)

        return True
