package gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import exception.DuplicateEntryException;
import listeners.CreateFrameAddElementListener;
import listeners.RemoveListElementEntityListener;
import model.Drawbox;
import model.Entity;
import model.Hitbox;
import repository.Project;

public class ListGUI extends JPanel {
	private Map<String, Icon> iconMap = new HashMap<>();
	JButton addListElementEntity;
	JButton removeListElementEntity;
	JList list;
	JScrollPane scroll;
	ActionListener removeEntity;
	ActionListener addEntity;
	DefaultListModel<String> testModel;
	JPanel gridButtonBar = new JPanel(new GridLayout(1, 2, 5, 0));
	private static Logger logger = Logger.getLogger("gui.ListGUI");
			 
    public ListGUI() {
    	setLayout(new BorderLayout());
    	setPreferredSize(new Dimension(223,638));
    	try {
			Project.getInstance().load();
		} catch (SAXException | IOException | ParserConfigurationException e) {
			// TODO: сделать нормальную обработку исключений - ситуации когда файл не существует, случилась ошибка парсинга и тд должны обрабатываться отдельно
			// в идеале должны появляться разные окошки, которые обрисуют в чём проблема и предложения что делать
			JOptionPane.showMessageDialog(this, "Parser exception, cause: "+e);
		}
    	String[] nameList = createNameList();  
        testModel = new DefaultListModel<>();
        list = new JList(testModel);
        list.setCellRenderer(new ListEntityRenderer());
        addEntity = new CreateFrameAddElementListener(this);       
        removeEntity = new RemoveListElementEntityListener(this);
        
        scroll = new JScrollPane(list);
        scroll.setLocation(5, 5);
        add(scroll,BorderLayout.CENTER);
        
        list.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        addListElementEntity = createButton(addEntity,"res/addbutton.png");
        removeListElementEntity = createButton(removeEntity,"res/deletebutton.png");
    	
        add(gridButtonBar,BorderLayout.SOUTH);
        
        /// ЧТОБЫ ОТКЛЮЧИТЬ ИЗБЫТОЧНЫЙ ВЫВОД В КОНСОЛЬ - НУЖНО СМЕНИТЬ УРОВЕНЬ ЛОГГИРОВАНИЯ В СТРОКЕ НИЖЕ
    	logger.setLevel(Level.FINEST);
    	// в идеале достаточно уровня WARNING, но если нужна более точна информация о модуле - можно снизить уровень
    	
        updateList();
    }
    
    public String getSelectedName() {
    	return (String) list.getSelectedValue();
    }
    

    public void addListElement(String name, String solid) throws DuplicateEntryException {
    	Entity e = new Entity(name);
    	e.setType(solid);
    	logger.finer("Entity \""+name+"\" was created.");
		Project.getInstance().addEntity(e);
    	updateList();
    }
    
	public void updateList() {
		testModel.removeAllElements();
		
		for (Entity e: Project.getInstance()) {
			testModel.addElement(e.getName());

		    // Create and store JList items icons in a map to prevent their unneccessary re-creation 
			iconMap.put(e.getName(), createListIconFromSprite( e.getImage() ));
		}
		
		list.updateUI();
	}

    /**
     * Функция, формирующая список имён сущностей для JList, чтобы сформировать его итемы
     * */
	private String[] createNameList() {
		//TODO: meh, хочется избавиться от использования списка - нехорошее это дело, лучше работать через интерфейс Project
		int index = 0, 
			size = Project.getInstance().getListEntity().size();
		String[] names = new String[size];
    	for(Entity e: Project.getInstance()) 
    		names[index++] = e.getName();
    	//TODO: не будет ли лучше хранить в JList не только имена, но и ссылки на сущности?
    	//было бы удобно по нажатию на итем JList'а сразу дёргать из него нужную сущность а
    	//из неё её хитбоксы и дроубоксы вместо вызовов по типу "Project.getInstance().getEntityByName(jListItem.getText())"
    	//НО! текущий вариант не требует написания кастомного JList, без которого в него целую сущность не запихать...
    	
    	return names;
    }
    private final float iconMaxWidth = 40, iconMaxHeight = 40;

	private Icon createListIconFromSprite(BufferedImage image) {
		CustomIcon icon = null;
		try {
			int imageWidth = image.getWidth(), imageHeight = image.getHeight();
			float scaleFactorX = iconMaxWidth / imageWidth, scaleFactorY = iconMaxHeight / imageHeight,
					scaleFactor = scaleFactorX < scaleFactorY ? scaleFactorX : scaleFactorY;
			// debug print
			// System.out.printf("ImageWidth: %d, ImageHeight: %d, scaleFactorX: %f,
			// scaleFactorY: %f, scaleFactor: %f \n", imageWidth, imageHeight, scaleFactorX,
			// scaleFactorY, scaleFactor);
			Image scaledImage = image.getScaledInstance((int) (imageWidth * scaleFactor),
					(int) (imageHeight * scaleFactor), Image.SCALE_SMOOTH);
			icon = new CustomIcon(scaledImage, (int) iconMaxWidth, (int) iconMaxHeight);
		} catch (NullPointerException npe) {
			logger.log(Level.WARNING, "Cannot scale icon for list item - the reference is null");
		}
		return icon;
	}
    
    public class ListEntityRenderer extends DefaultListCellRenderer 
    {
        Font font = new Font("helvitica", Font.BOLD, 14);

        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) 
        {
        	int iconTextOffset = 10;
        	
            JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            Entity e = null;
			try {
				e = Project.getInstance().getEntityByName((String)value);
	            String text = label.getText();
	            text = "<html>"+text+"<br>"+"<small>"+e.getType()+"</small>";
	            label.setText(text);
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			Icon icon = iconMap.get((String) value);
			if(icon != null) {
				label.setIcon(icon);
				label.setIconTextGap((int)iconMaxWidth - icon.getIconWidth() + iconTextOffset);
			}
            label.setFont(font);
            return label;
        }
    }

    private JButton createButton(ActionListener listener,String pathImage) {
		JButton button = new JButton(new ImageIcon(pathImage));
		button.setPreferredSize(new Dimension(100, 50));
		button.addActionListener(listener); 
		button.setContentAreaFilled(false);
		button.setFocusPainted(false);
		gridButtonBar.add(button);	
		return button;
	}
    
    /**
     * Немного костыль, который позволяет зарегестрировать слушатель мыши на списке компонентов
     * не создавая излишне тесных связей между компонентами
     * */
    public void registerJListListener(ListSelectionListener ml) {
    	list.addListSelectionListener(ml);
    }
    
   public void printNameList(String[] nameList) {
	   System.out.println("вызван принт лист: "+nameList.length);
	   for(int i = 0;i<nameList.length;i++) {
		   System.out.println(nameList[i]);
	   }
    }
}
