// Path: src/main/java/me/desht/scrollingmenusign/views/SMSMapView.java
// public class SMSMapRenderer extends MapRenderer {
//     private final SMSMapView view;
// 
//     public SMSMapRenderer(SMSMapView view) {
//         super(true);
//         this.view = view;
//     }
// 
//     public SMSMapView getView() {
//         return view;
//     }
// 
//     @Override
//     public void render(MapView map, MapCanvas canvas, Player player) {
//         if (isDirty(player)) {
//             BufferedImage img = renderImage(player);
//             canvas.drawImage(0, 0, img);
//             setDirty(player, false);
//             player.sendMap(map);
//         }
//     }
// }
// 
// Path: src/main/java/me/desht/scrollingmenusign/views/SMSView.java
// public class MenuStack {
//     final Deque<WeakReference<SMSMenu>> stack;
// 
//     public MenuStack() {
//         stack = new ArrayDeque<WeakReference<SMSMenu>>();
//     }
// 
//     public void pushMenu(SMSMenu menu) {
//         stack.push(new WeakReference<SMSMenu>(menu));
//     }
// 
//     public SMSMenu popMenu() {
//         return stack.pop().get();
//     }
// 
//     public SMSMenu peek() {
//         return stack.peek().get();
//     }
// 
//     public boolean isEmpty() {
//         return stack.isEmpty();
//     }
// }
// 
// Path: src/main/java/me/desht/scrollingmenusign/views/action/RepaintAction.java
// public class RepaintAction extends ViewUpdateAction {
//     public RepaintAction() {
//         super();
//     }
// 
//     public RepaintAction(CommandSender sender) {
//         super(sender);
//     }
// }


import me.desht.dhutils.Debugger;
import me.desht.dhutils.LogUtils;
import me.desht.dhutils.block.BlockUtil;
import me.desht.scrollingmenusign.*;
import me.desht.scrollingmenusign.views.SMSMapView.SMSMapRenderer;
import me.desht.scrollingmenusign.views.SMSView.MenuStack;
import me.desht.scrollingmenusign.views.action.RepaintAction;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
import org.bukkit.util.Vector;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.Map.Entry;
    public void loadDeferred(World world) {
        for (SMSView view : listViews()) {
            List<Vector> l = view.getDeferredLocations(world.getName());
            if (l == null) {
                continue;
            }

            for (Vector vec : l) {
                try {
                    view.addLocation(new Location(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()));
                    Debugger.getInstance().debug("added loc " + world.getName() + ", " + vec + " to view " + view.getName());
                } catch (SMSException e) {
                    LogUtils.warning("Can't add location " + world.getName() + ", " + vec + " to view " + view.getName());
                    LogUtils.warning("  Exception message: " + e.getMessage());
                }
            }
            l.clear();
        }
    }

    /**
     * Given a map ID, return the map view object for that ID, if any.
     *
     * @param mapId The ID of the map
     * @return The SMSMapView object for the ID, or null if this map ID isn't used for a SMSMapView
     */
    public SMSMapView getMapViewForId(short mapId) {
        MapView mv = Bukkit.getMap(mapId);
        if (mv != null) {
            for (MapRenderer r : mv.getRenderers()) {
// Path: src/main/java/me/desht/scrollingmenusign/views/SMSMapView.java
// public class SMSMapRenderer extends MapRenderer {
//     private final SMSMapView view;
// 
//     public SMSMapRenderer(SMSMapView view) {
//         super(true);
//         this.view = view;
//     }
// 
//     public SMSMapView getView() {
//         return view;
//     }
// 
//     @Override
//     public void render(MapView map, MapCanvas canvas, Player player) {
//         if (isDirty(player)) {
//             BufferedImage img = renderImage(player);
//             canvas.drawImage(0, 0, img);
//             setDirty(player, false);
//             player.sendMap(map);
//         }
//     }
// }
// 
// Path: src/main/java/me/desht/scrollingmenusign/views/SMSView.java
// public class MenuStack {
//     final Deque<WeakReference<SMSMenu>> stack;
// 
//     public MenuStack() {
//         stack = new ArrayDeque<WeakReference<SMSMenu>>();
//     }
// 
//     public void pushMenu(SMSMenu menu) {
//         stack.push(new WeakReference<SMSMenu>(menu));
//     }
// 
//     public SMSMenu popMenu() {
//         return stack.pop().get();
//     }
// 
//     public SMSMenu peek() {
//         return stack.peek().get();
//     }
// 
//     public boolean isEmpty() {
//         return stack.isEmpty();
//     }
// }
// 
// Path: src/main/java/me/desht/scrollingmenusign/views/action/RepaintAction.java
// public class RepaintAction extends ViewUpdateAction {
//     public RepaintAction() {
//         super();
//     }
// 
//     public RepaintAction(CommandSender sender) {
//         super(sender);
//     }
// }


// Path: src/main/java/me/desht/scrollingmenusign/views/ViewManager.java
import me.desht.dhutils.Debugger;
import me.desht.dhutils.LogUtils;
import me.desht.dhutils.block.BlockUtil;
import me.desht.scrollingmenusign.*;
import me.desht.scrollingmenusign.views.SMSMapView.SMSMapRenderer;
import me.desht.scrollingmenusign.views.SMSView.MenuStack;
import me.desht.scrollingmenusign.views.action.RepaintAction;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
import org.bukkit.util.Vector;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.Map.Entry;

    public void loadDeferred(World world) {
        for (SMSView view : listViews()) {
            List<Vector> l = view.getDeferredLocations(world.getName());
            if (l == null) {
                continue;
            }

            for (Vector vec : l) {
                try {
                    view.addLocation(new Location(world, vec.getBlockX(), vec.getBlockY(), vec.getBlockZ()));
                    Debugger.getInstance().debug("added loc " + world.getName() + ", " + vec + " to view " + view.getName());
                } catch (SMSException e) {
                    LogUtils.warning("Can't add location " + world.getName() + ", " + vec + " to view " + view.getName());
                    LogUtils.warning("  Exception message: " + e.getMessage());
                }
            }
            l.clear();
        }
    }

    /**
     * Given a map ID, return the map view object for that ID, if any.
     *
     * @param mapId The ID of the map
     * @return The SMSMapView object for the ID, or null if this map ID isn't used for a SMSMapView
     */
    public SMSMapView getMapViewForId(short mapId) {
        MapView mv = Bukkit.getMap(mapId);
        if (mv != null) {
            for (MapRenderer r : mv.getRenderers()) {
                if (r instanceof SMSMapRenderer) {