use crate::document::{Document, DocumentState, ActionHistory};
use crate::editorgui::{Packages, ResourceType};

use std::collections::HashSet;
use std::any::Any;

use keeshond::gameloop::GameControl;
use keeshond::renderer::Sheet;

use keeshond_datapack::DataId;
use keeshond_treats::tilemap::{Tileset, TilesetTile, TileCollision, TileBoundingBoxData};
use keeshond_treats::visual::{SheetSource, SliceIndexSource};

use imgui::{im_str, Window, Ui, TabBarFlags, StyleColor};


enum TilesetAction
{
    SetSheet(String, String),
    SetTileSize(f32, f32),
    AddTile(usize, TilesetTile),
    AddTiles(usize, Vec<TilesetTile>),
    SetTile(usize, TilesetTile),
    MoveTile(usize, usize),
    RemoveTile(usize),
    RenameFlag(usize, String)
}

pub struct TilesetDocument
{
    action_history : ActionHistory,
    data_id : DataId,
    current_tile : usize,
    extra_selection : HashSet<usize>,
    left_column_set : bool,
    transparent_color : [f32; 3],
    zoom_level : f32,
    show_colliders_in_list : bool,
    scroll_tile_list : bool
}

impl TilesetDocument
{
    fn add_tile(&mut self, index : usize, tileset : &mut Tileset, tile : TilesetTile) -> bool
    {
        let mut target_tile = 0;

        if tileset.tile_count() > 0
        {
            target_tile = index + 1;
        }

        if tileset.insert_tile(target_tile, tile.clone())
        {
            self.current_tile += 1;
            return true;
        }

        false
    }

    fn add_tiles(&mut self, index : usize, tileset : &mut Tileset, tiles : &Vec<TilesetTile>) -> bool
    {
        if tiles.is_empty()
        {
            return false;
        }

        let mut target_tile = 0;
        let mut result = false;

        if tileset.tile_count() > 0
        {
            target_tile = index + 1;
        }

        for tile in tiles
        {
            if tileset.insert_tile(target_tile, tile.clone())
            {
                target_tile += 1;
                self.current_tile += 1;

                result = true;
            }
        }

        result
    }

    fn move_tile(&mut self, tileset : &mut Tileset, old : usize, new : usize) -> bool
    {
        if new >= tileset.tile_count()
        {
            return false;
        }

        if let Some(tile) = tileset.tile(old).cloned()
        {
            tileset.remove_tile(old);
            tileset.insert_tile(new, tile);

            self.current_tile = new;

            return true;
        }

        false
    }

    fn image_from_slice(tileset: &mut Tileset, texture_id : usize, sheet_opt : Option<&Sheet>, slice : usize, image_size : [f32; 2]) -> imgui::Image
    {
        if let Some(sheet) = sheet_opt
        {
            if let Some(index) = tileset.updated_slice_id(slice, sheet)
            {
                if let Some(slice) = sheet.slice(index)
                {
                    return imgui::Image::new(imgui::TextureId::from(texture_id), image_size)
                        .uv0([slice.texture_x / sheet.width() as f32,
                            slice.texture_y / sheet.height() as f32])
                        .uv1([(slice.texture_x + slice.texture_w) / sheet.width() as f32,
                            (slice.texture_y + slice.texture_h) / sheet.height() as f32]);
                }
                else
                {
                    return imgui::Image::new(imgui::TextureId::from(0), image_size);
                }
            }
            else
            {
                return imgui::Image::new(imgui::TextureId::from(usize::MAX), image_size)
                    .uv0([0.0, 0.0]).uv1([0.0, 0.0]);
            }
        }

        return imgui::Image::new(imgui::TextureId::from(0), image_size);
    }

    fn draw_collision_shape(&mut self, pos : [f32; 2], size : [f32; 2], zoom : f32, draw_list : &imgui::WindowDrawList, tile : &TilesetTile)
    {
        draw_list.add_rect([pos[0], pos[1]], [pos[0] + size[0], pos[1] + size[1]], imgui::ImColor::from([0.0, 0.0, 0.0, 0.25])).filled(true).build();

        match tile.collision()
        {
            TileCollision::None => {}
            TileCollision::BoundingBox(bounding_box) =>
            {
                let x1 = (pos[0] + bounding_box.x1 * zoom).max(pos[0]).min(pos[0] + size[0]);
                let y1 = (pos[1] + bounding_box.y1 * zoom).max(pos[1]).min(pos[1] + size[1]);
                let x2 = (pos[0] + bounding_box.x2 * zoom).max(pos[0]).min(pos[0] + size[0]);
                let y2 = (pos[1] + bounding_box.y2 * zoom).max(pos[1]).min(pos[1] + size[1]);

                draw_list.add_rect([x1, y1], [x2, y2], imgui::ImColor::from([1.0, 1.0, 1.0, 0.25])).filled(true).build();
                draw_list.add_rect([x1, y1], [x2, y2], imgui::ImColor::from([1.0, 1.0, 1.0, 1.0])).thickness(1.0).build();
            }
        }
    }
}

impl Document for TilesetDocument
{
    fn load(game : &mut GameControl, package_name : &str, item_name : &str) -> Self where Self : Sized
    {
        let mut data_id = 0;

        if let Ok(id) = game.res().store_mut::<Tileset>().get_id_mut(package_name, item_name)
        {
            data_id = id;
        }

        TilesetDocument
        {
            action_history: ActionHistory::new(),
            data_id,
            current_tile : 0,
            extra_selection : HashSet::new(),
            left_column_set : false,
            transparent_color : [0.5, 0.5001, 0.5002],
            zoom_level : 1.0,
            show_colliders_in_list : true,
            scroll_tile_list : false
        }
    }

    fn action_history(&mut self) -> &mut ActionHistory
    {
        &mut self.action_history
    }

    fn apply_action(&mut self, game : &mut GameControl, action : &Box<dyn Any>) -> bool
    {
        if let Some(action) = action.downcast_ref::<TilesetAction>()
        {
            let mut tileset_store = game.res().store_mut::<Tileset>();

            if let Some(tileset) = tileset_store.get_mut(self.data_id)
            {
                match action
                {
                    TilesetAction::SetSheet(package, name) =>
                    {
                        tileset.set_sheet_source(SheetSource::new(&package, &name));
                        return true;
                    },
                    TilesetAction::SetTileSize(width, height) =>
                    {
                        self.scroll_tile_list = true;
                        tileset.set_tile_size(*width, *height);
                        return true;
                    },
                    TilesetAction::AddTile(index, tile) =>
                    {
                        self.scroll_tile_list = true;
                        return self.add_tile(*index, tileset, tile.clone());
                    },
                    TilesetAction::AddTiles(index, tiles) =>
                    {
                        self.scroll_tile_list = true;
                        return self.add_tiles(*index, tileset, tiles);
                    }
                    TilesetAction::SetTile(index, tile) =>
                    {
                        self.scroll_tile_list = true;
                        return tileset.set_tile(*index, tile.clone());
                    },
                    TilesetAction::MoveTile(old_index, new_index) =>
                    {
                        self.scroll_tile_list = true;
                        return self.move_tile(tileset, *old_index, *new_index);
                    },
                    TilesetAction::RemoveTile(index) =>
                    {
                        self.scroll_tile_list = true;
                        return tileset.remove_tile(*index).is_some();
                    },
                    TilesetAction::RenameFlag(flag, name) =>
                    {
                        return tileset.set_flag_name(*flag, name);
                    }
                }
            }
        }

        false
    }

    fn do_ui(&mut self, packages : &mut Packages, game : &mut GameControl, window_builder : Window, ui : &mut Ui) -> DocumentState
    {
        let mut result = DocumentState::new();
        let sheet_store = game.res().store_mut::<Sheet>();
        let mut tileset_store = game.res().store_mut::<Tileset>();

        window_builder.menu_bar(true).build(ui, ||
        {
            ui.menu_bar(||
            {
                ui.menu(im_str!("View"), true, ||
                {
                    if imgui::MenuItem::new(im_str!("Show Collision Shapes in Tile List")).selected(self.show_colliders_in_list).build(ui)
                    {
                        self.show_colliders_in_list = !self.show_colliders_in_list;
                    }

                    ui.menu(im_str!("Background Color"), true, ||
                    {
                        imgui::ColorPicker::new(im_str!("##background_color_picker"), imgui::EditableColor::Float3(&mut self.transparent_color)).build(ui);
                    });
                });
                ui.menu(im_str!("Zoom"), true, ||
                {
                    for level in &[0.25, 0.5, 1.0, 2.0, 3.0, 4.0, 6.0, 8.0, 10.0, 12.0, 16.0]
                    {
                        if imgui::MenuItem::new(&im_str!("{}%", (level * 100.0) as i32)).selected(self.zoom_level == *level).build(ui)
                        {
                            self.zoom_level = *level;
                        }
                    }
                });
            });

            result.active = ui.is_window_focused();

            if let Some(tileset) = tileset_store.get_mut(self.data_id)
            {
                let main_style = ui.clone_style();
                let mut texture_id = 0;
                let source = tileset.sheet_source();
                let sheet_opt = match sheet_store.get_id(source.package(), source.sheet())
                {
                    Ok(index) =>
                    {
                        texture_id = index;
                        sheet_store.get(index)
                    }
                    Err(_) =>
                    {
                        packages.load_package_later(ResourceType::Sheet, source.package());
                        None
                    }
                };

                let mut package_name = imgui::ImString::with_capacity(4096);
                let mut sheet_name = imgui::ImString::with_capacity(4096);

                package_name.push_str(source.package());
                sheet_name.push_str(source.sheet());

                ui.columns(2, im_str!("##tileset_columns"), true);

                if !self.left_column_set
                {
                    ui.set_current_column_width(290.0);
                    self.left_column_set = true;
                }

                let mut collision_open = false;
                let mut flag_names_open = false;

                imgui::ChildWindow::new("tileset_controls").size([0.0, 0.0]).draw_background(true).border(false).horizontal_scrollbar(true).build(ui, ||
                {
                    self.current_tile = self.current_tile.min(tileset.tile_count().max(1) - 1);

                    imgui::TabBar::new(im_str!("tileset_tabbar"))
                        .flags(TabBarFlags::FITTING_POLICY_SCROLL).build(ui, ||
                    {
                        imgui::TabItem::new(im_str!("Slices")).build(ui, ||
                        {
                            let mut update_sheet = false;

                            update_sheet |= ui.input_text(im_str!("Package"), &mut package_name).enter_returns_true(true).build();
                            update_sheet |= ui.input_text(im_str!("Sheet"), &mut sheet_name).enter_returns_true(true).build();

                            if update_sheet
                            {
                                self.queue_action(Box::new(TilesetAction::SetSheet(package_name.to_string(), sheet_name.to_string())));
                            }

                            let (width, height) = tileset.tile_size();
                            let mut sizes = [width, height];

                            if imgui::Drag::new(im_str!("Tile Size")).display_format(im_str!("%.4f")).build_array(ui, &mut sizes)
                            {
                                self.queue_action(Box::new(TilesetAction::SetTileSize(sizes[0], sizes[1])));
                            }

                            if let Some(sheet) = sheet_opt
                            {
                                if let Some(slice) = sheet.slice(0)
                                {
                                    if width != slice.texture_w || height != slice.texture_h
                                    {
                                        ui.same_line(0.0);

                                        if ui.button(im_str!("!###tile_size_auto"), [0.0, 0.0])
                                        {
                                            self.queue_action(Box::new(TilesetAction::SetTileSize(slice.texture_w, slice.texture_h)));
                                        }
                                    }
                                }
                            }

                            ui.spacing();
                            ui.separator();
                            ui.spacing();
                            ui.text(&im_str!("Editing Tile {}", self.current_tile));

                            ui.spacing();

                            if let Some(sheet) = sheet_opt
                            {
                                if self.current_tile < tileset.tile_count()
                                {
                                    let index_opt = tileset.updated_slice_id(self.current_tile, sheet);
                                    let mut has_slice = index_opt.is_some();

                                    if ui.checkbox(im_str!("Has Slice"), &mut has_slice)
                                    {
                                        let mut tile = tileset.tile(self.current_tile).expect("Current tile vanished!").clone();

                                        if has_slice
                                        {
                                            tile.set_slice_source(Some(SliceIndexSource::with_index(0)));
                                        }
                                        else
                                        {
                                            tile.set_slice_source(None);
                                        }

                                        self.queue_action(Box::new(TilesetAction::SetTile(self.current_tile, tile)));
                                    }

                                    if let Some(index) = index_opt
                                    {
                                        let mut index_slider = index as u32;
                                        let mut slice_name = imgui::ImString::with_capacity(4096);

                                        if let Some(name) = tileset.slice_name(self.current_tile)
                                        {
                                            slice_name.push_str(name);
                                        }

                                        let width = ui.push_item_width(48.0);
                                        if imgui::Drag::new(im_str!("Index###slice_index")).build(ui, &mut index_slider)
                                        {
                                            let mut tile = tileset.tile(self.current_tile).expect("Current tile vanished!").clone();
                                            tile.set_slice_source(Some(SliceIndexSource::with_index(index_slider as usize)));

                                            self.queue_action(Box::new(TilesetAction::SetTile(self.current_tile, tile)));
                                        }
                                        width.pop(ui);

                                        ui.same_line(0.0);

                                        let width = ui.push_item_width(128.0);
                                        if ui.input_text(im_str!("Name###slice_name"), &mut slice_name).build()
                                        {
                                            let mut tile = tileset.tile(self.current_tile).expect("Current tile vanished!").clone();
                                            tile.set_slice_source(Some(SliceIndexSource::with_name(slice_name.to_str())));

                                            self.queue_action(Box::new(TilesetAction::SetTile(self.current_tile, tile)));
                                        }
                                        width.pop(ui);
                                    }
                                    else
                                    {
                                        ui.invisible_button(im_str!("###slice_placeholder"), [100.0, ui.current_font_size() + main_style.frame_padding[1] * 2.0]);
                                    }
                                }

                                if ui.button(im_str!("Create Tiles From Unused Slices"), [0.0, 0.0])
                                {
                                    let mut tiles = Vec::new();
                                    let mut used = HashSet::new();

                                    let num_slices = sheet.slice_count();
                                    let num_tiles = tileset.tile_count();

                                    for i in 0..num_tiles
                                    {
                                        if let Some(id) = tileset.updated_slice_id(i, sheet)
                                        {
                                            used.insert(id);
                                        }
                                    }

                                    for i in 0..num_slices
                                    {
                                        if !used.contains(&i)
                                        {
                                            tiles.push(TilesetTile::new(Some(SliceIndexSource::with_index(i))));
                                        }
                                    }

                                    self.queue_action(Box::new(TilesetAction::AddTiles(self.current_tile.max(1) - 1, tiles)));
                                }
                            }
                        });

                        imgui::TabItem::new(im_str!("Collision")).build(ui, ||
                        {
                            collision_open = true;

                            ui.text(&im_str!("Editing Tile {}", self.current_tile));

                            if self.extra_selection.len() > 0
                            {
                                ui.same_line(0.0);

                                if ui.small_button(&im_str!("Copy To {} Others###collision_copy", self.extra_selection.len()))
                                {
                                    if let Some(tile) = tileset.tile(self.current_tile)
                                    {
                                        let collision = tile.collision().clone();

                                        for i in &self.extra_selection.clone()
                                        {
                                            if let Some(mut other_tile) = tileset.tile(*i).cloned()
                                            {
                                                other_tile.set_collision(collision.clone());

                                                self.queue_action(Box::new(TilesetAction::SetTile(*i, other_tile)));
                                            }
                                        }
                                    }
                                }
                            }

                            ui.spacing();

                            imgui::ChildWindow::new("tileset_collision_controls").size([0.0, 160.0]).draw_background(false).border(false).build(ui, ||
                            {
                                if let Some(tile) = tileset.tile(self.current_tile)
                                {
                                    let mut index = match tile.collision()
                                    {
                                        TileCollision::None => { 0 }
                                        TileCollision::BoundingBox(_) => { 1 }
                                    };

                                    if imgui::ComboBox::new(im_str!("Collision Type"))
                                        .build_simple_string(ui, &mut index, &[im_str!("None"), im_str!("Bounding Box")])
                                    {
                                        let mut new_tile = tile.clone();
                                        let (width, height) = tileset.tile_size();
                                        let collision = match index
                                        {
                                            0 => TileCollision::None,
                                            1 => TileCollision::BoundingBox(TileBoundingBoxData::from_width_height(width, height)),
                                            _ => panic!("Unknown collision tile index")
                                        };

                                        new_tile.set_collision(collision);

                                        self.queue_action(Box::new(TilesetAction::SetTile(self.current_tile, new_tile)));
                                    }

                                    match tile.collision()
                                    {
                                        TileCollision::None => {},
                                        TileCollision::BoundingBox(bounding_box) =>
                                        {
                                            let mut new_box = bounding_box.clone();
                                            let mut modified = false;
                                            let mut x_bounds = [new_box.x1, new_box.x2];
                                            let mut y_bounds = [new_box.y1, new_box.y2];

                                            modified |= imgui::Drag::new(im_str!("X Bounds")).display_format(im_str!("%.4f")).build_array(ui, &mut x_bounds);
                                            modified |= imgui::Drag::new(im_str!("Y Bounds")).display_format(im_str!("%.4f")).build_array(ui, &mut y_bounds);

                                            ui.spacing();
                                            ui.spacing();
                                            ui.text(im_str!("Solidity"));

                                            ui.spacing();

                                            modified |= ui.checkbox(im_str!("Top###solid_top"), &mut new_box.solid_top);
                                            ui.same_line(0.0);
                                            modified |= ui.checkbox(im_str!("Bottom###solid_bottom"), &mut new_box.solid_bottom);
                                            ui.same_line(0.0);
                                            modified |= ui.checkbox(im_str!("Left###solid_left"), &mut new_box.solid_left);
                                            ui.same_line(0.0);
                                            modified |= ui.checkbox(im_str!("Right###solid_right"), &mut new_box.solid_right);

                                            if modified
                                            {
                                                let mut new_tile = tile.clone();
                                                new_box.x1 = x_bounds[0];
                                                new_box.x2 = x_bounds[1];
                                                new_box.y1 = y_bounds[0];
                                                new_box.y2 = y_bounds[1];
                                                new_tile.set_collision(TileCollision::BoundingBox(new_box));
                                                self.queue_action(Box::new(TilesetAction::SetTile(self.current_tile, new_tile)));
                                            }
                                        }
                                    }
                                }
                            });
                        });

                        imgui::TabItem::new(im_str!("Flags")).build(ui, ||
                        {
                            ui.text(&im_str!("Editing Tile {}", self.current_tile));

                            if self.extra_selection.len() > 0
                            {
                                ui.same_line(0.0);

                                if ui.small_button(&im_str!("Copy To {} Others###flag_copy", self.extra_selection.len()))
                                {
                                    if let Some(tile) = tileset.tile(self.current_tile)
                                    {
                                        let flags = tile.flags();

                                        for i in &self.extra_selection.clone()
                                        {
                                            if let Some(mut other_tile) = tileset.tile(*i).cloned()
                                            {
                                                other_tile.set_flags(flags);

                                                self.queue_action(Box::new(TilesetAction::SetTile(*i, other_tile)));
                                            }
                                        }
                                    }
                                }
                            }

                            ui.spacing();

                            imgui::ChildWindow::new("tileset_flag_controls").size([0.0, 306.0]).draw_background(false).border(false).build(ui, ||
                            {
                                for i in 0..32
                                {
                                    if let Some(tile) = tileset.tile(self.current_tile)
                                    {
                                        let mut flag_name = imgui::ImString::with_capacity(4096);

                                        if let Some(name) = tileset.flag_name(i)
                                        {
                                            flag_name.push_str(name);
                                        }

                                        if flag_name.is_empty()
                                        {
                                            flag_name.push_str(&format!("<flag {}>", i));
                                        }

                                        let mut flag_value = tile.flag(i);

                                        if ui.checkbox(&flag_name, &mut flag_value)
                                        {
                                            let mut new_tile = tile.clone();

                                            new_tile.set_flag(i, flag_value);

                                            self.queue_action(Box::new(TilesetAction::SetTile(self.current_tile, new_tile)));
                                        }
                                    }
                                }
                            });
                        });

                        imgui::TabItem::new(im_str!("Flag Names")).build(ui, ||
                        {
                            flag_names_open = true;

                            for i in 0..32
                            {
                                if let Some(name) = tileset.flag_name(i)
                                {
                                    let mut flag_name = imgui::ImString::with_capacity(4096);

                                    flag_name.push_str(name);

                                    if ui.input_text(&im_str!("Flag {}", i), &mut flag_name).enter_returns_true(true).build()
                                    {
                                        self.queue_action(Box::new(TilesetAction::RenameFlag(i, flag_name.to_string())));
                                    }
                                }
                            }
                        });
                    });

                    if !flag_names_open
                    {
                        ui.spacing();
                        ui.separator();
                        ui.spacing();

                        imgui::ChildWindow::new("tile_view").size([0.0, 0.0]).movable(false).build(ui, ||
                        {
                            if ui.button(im_str!("Add"), [0.0, 0.0])
                            {
                                let new_tile;

                                if let Some(tile) = tileset.tile(self.current_tile)
                                {
                                    new_tile = tile.clone();
                                }
                                else
                                {
                                    new_tile = TilesetTile::new(None);
                                }

                                self.queue_action(Box::new(TilesetAction::AddTile(self.current_tile, new_tile)));
                            }
                            ui.same_line_with_spacing(0.0, 4.0);
                            if ui.button(im_str!("Up"), [0.0, 0.0]) && self.current_tile > 0
                            {
                                self.queue_action(Box::new(TilesetAction::MoveTile(self.current_tile, self.current_tile - 1)));
                            }
                            ui.same_line_with_spacing(0.0, 4.0);
                            if ui.button(im_str!("Down"), [0.0, 0.0])
                            {
                                self.queue_action(Box::new(TilesetAction::MoveTile(self.current_tile, self.current_tile + 1)));
                            }
                            ui.same_line_with_spacing(0.0, 4.0);
                            if ui.button(im_str!("Remove"), [0.0, 0.0])
                            {
                                self.queue_action(Box::new(TilesetAction::RemoveTile(self.current_tile)));
                            }

                            let style_slice_list = ui.push_style_var(imgui::StyleVar::WindowPadding([1.0, 1.0]));
                            let colors_slice_list = ui.push_style_color(imgui::StyleColor::ChildBg, [self.transparent_color[0], self.transparent_color[1], self.transparent_color[2], 1.0]);

                            imgui::ChildWindow::new("tile_list").always_vertical_scrollbar(true).border(true).draw_background(true).build(ui, ||
                            {
                                let style_slice = ui.push_style_var(imgui::StyleVar::ItemSpacing([0.0, 0.0]));
                                let num_tiles = tileset.tile_count();

                                let start_pos = ui.cursor_screen_pos();

                                let (orig_tile_width, orig_tile_height) = tileset.tile_size();
                                let mut tile_width = orig_tile_width * self.zoom_level;
                                let mut tile_height = orig_tile_height * self.zoom_level;
                                let base_width = tile_width.max(1.0);

                                tile_width = tile_width.max(8.0).min(128.0);
                                tile_height = tile_height.max(1.0);

                                if tile_width != base_width
                                {
                                    tile_height *= tile_width / base_width;
                                    tile_height = tile_height.max(1.0);
                                }

                                let button_size = [tile_width, tile_height];
                                let layout_width = ui.column_width(0) - 2.0;
                                let columns = (layout_width / tile_width).floor().max(1.0) as usize;

                                for i in 0..num_tiles
                                {
                                    if i % columns > 0
                                    {
                                        ui.same_line(0.0);
                                    }

                                    let cursor_pos = ui.cursor_pos();
                                    TilesetDocument::image_from_slice(tileset, texture_id, sheet_opt, i, button_size).build(ui);

                                    ui.set_cursor_pos([cursor_pos[0], cursor_pos[1]]);

                                    if imgui::Selectable::new(&im_str!("###tile_{}", i))
                                        .selected(self.current_tile == i || self.extra_selection.contains(&i)).size(button_size).build(ui)
                                    {
                                        if ui.io().key_ctrl
                                        {
                                            if self.current_tile != i
                                            {
                                                if self.extra_selection.contains(&i)
                                                {
                                                    self.extra_selection.remove(&i);
                                                }
                                                else
                                                {
                                                    self.extra_selection.insert(i);
                                                }
                                            }
                                        }
                                        else
                                        {
                                            self.extra_selection.clear();
                                            self.current_tile = i;
                                        }
                                    }

                                    if self.current_tile == i && self.scroll_tile_list
                                    {
                                        ui.set_scroll_here_y();
                                        self.scroll_tile_list = false;
                                    }

                                    if ui.is_item_hovered()
                                    {
                                        ui.tooltip_text(&im_str!("Tile {}", i));
                                    }
                                }

                                if collision_open && self.show_colliders_in_list
                                {
                                    let draw_list = ui.get_window_draw_list();

                                    for i in 0..num_tiles
                                    {
                                        let x = start_pos[0] + (i % columns) as f32 * tile_width;
                                        let y = start_pos[1] + (i / columns) as f32 * tile_height;
                                        let zoom = tile_width / orig_tile_width;

                                        if let Some(tile) = tileset.tile(i)
                                        {
                                            self.draw_collision_shape([x, y], button_size, zoom, &draw_list, tile)
                                        }
                                    }
                                }

                                let x1 = start_pos[0] + (self.current_tile % columns) as f32 * tile_width;
                                let y1 = start_pos[1] + (self.current_tile / columns) as f32 * tile_height;
                                let x2 = x1 + tile_width;
                                let y2 = y1 + tile_height;

                                let draw_list = ui.get_window_draw_list();

                                draw_list.add_rect([x1, y1], [x2, y2], main_style.colors[StyleColor::Button as usize]).thickness(2.0).build();

                                style_slice.pop(ui);
                            });

                            colors_slice_list.pop(ui);
                            style_slice_list.pop(ui);
                        });
                    }
                });

                ui.next_column();

                let remaining = ui.content_region_avail();
                let (tile_width, tile_height) = tileset.tile_size();
                let zoom = (remaining[0] / tile_width).min(remaining[1] / tile_height).floor().max(1.0).min(16.0);
                let size = [zoom * tile_width, zoom * tile_height];

                let style_tile_view = ui.push_style_var(imgui::StyleVar::WindowPadding([1.0, 1.0]));
                let colors_tile_view = ui.push_style_color(imgui::StyleColor::ChildBg, [self.transparent_color[0], self.transparent_color[1], self.transparent_color[2], 1.0]);

                imgui::ChildWindow::new("tileset_tile_view").size([size[0] + 2.0, size[1] + 2.0])
                    .draw_background(true).border(true).build(ui, ||
                {
                    let pos = ui.cursor_screen_pos();
                    let draw_list = ui.get_window_draw_list();

                    TilesetDocument::image_from_slice(tileset, texture_id, sheet_opt, self.current_tile, size).build(ui);

                    if collision_open
                    {
                        if let Some(tile) = tileset.tile(self.current_tile)
                        {
                            self.draw_collision_shape(pos, size, zoom, &draw_list, tile);
                        }
                    }
                });

                colors_tile_view.pop(ui);
                style_tile_view.pop(ui);
            }
        });

        result
    }
}
