package geisplugin.popup.actions;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Robot;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Stream;

import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.filechooser.FileSystemView;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import geisplugin.Activator;
import geisplugin.Tools;

/**
 * DE: 
 *
 * EN: 
 * 
 * 
 * Program changes
 * **************************************************************************************
 * Date			* Ticket	* KonzFirm	* Responsible	* programmer    *
 * Change										*
 * **************************************************************************************
 *
 * @author huellmante
 * @version 1.0
 *
 */

public class GenerateHibernateMapping {
	
	private final static Color alt = new Color(245, 245, 245);
	private final static Color selectionBackgroundColor = new Color(51, 153, 255);
	
	public class MyListCellThing extends JLabel implements ListCellRenderer<String> {

		private static final long serialVersionUID = 1L;

		public MyListCellThing() {
	        setOpaque(true);
	    }

		@Override
		public Component getListCellRendererComponent(JList<? extends String> list, String value, int index, boolean isSelected, boolean cellHasFocus) {
			setText(value.toString());
			if (isSelected) {
				setBackground(selectionBackgroundColor);
				setForeground(Color.white);
			} else {
				setForeground(Color.black);
				if (index % 2 == 0) {
					setBackground(Color.white);
				} else {
					setBackground(alt);
				}
			}
	        return this;
		}
	}

	private static Shell shell = null;
	
	public static class FilteredListModel extends AbstractListModel<String> {

		private static final long serialVersionUID = 1L;

		public static interface Filter {
	        boolean accept(Object element);
	    }

	    private final ListModel<String> _source;
	    private Filter _filter;
	    private final ArrayList<Integer> _indices = new ArrayList<Integer>();

	    public FilteredListModel(ListModel<String> source) {
	        if (source == null)
	            throw new IllegalArgumentException("Source is null");
	        _source = source;
	        _source.addListDataListener(new ListDataListener() {
	            @Override
				public void intervalRemoved(ListDataEvent e) {
	                doFilter();
	            }

	            @Override
				public void intervalAdded(ListDataEvent e) {
	                doFilter();
	            }

	            @Override
				public void contentsChanged(ListDataEvent e) {
	                doFilter();
	            }
	        });
	    }

	    public void setFilter(Filter f) {
	        _filter = f;
	        doFilter();
	    }

	    private void doFilter() {
	        _indices.clear();

	        Filter f = _filter;
	        if (f != null) {
	            int count = _source.getSize();
	            for (int i = 0; i < count; i++) {
	                Object element = _source.getElementAt(i);
	                if (f.accept(element)) {
	                    _indices.add(i);
	                }
	            }
	            fireContentsChanged(this, 0, getSize() - 1);
	        }
	    }

	    @Override
		public int getSize() {
	        return (_filter != null) ? _indices.size() : _source.getSize();
	    }

	    @Override
		public String getElementAt(int index) {
	        return (_filter != null) ? _source.getElementAt(_indices.get(index)) : _source.getElementAt(index);
	    }
	}
	
	public static class RequestFocusListener implements AncestorListener
	{
		private boolean removeListener;

		/*
		 *  Convenience constructor. The listener is only used once and then it is
		 *  removed from the component.
		 */
		public RequestFocusListener()
		{
			this(true);
		}

		/*
		 *  Constructor that controls whether this listen can be used once or
		 *  multiple times.
		 *
		 *  @param removeListener when true this listener is only invoked once
		 *                        otherwise it can be invoked multiple times.
		 */
		public RequestFocusListener(boolean removeListener)
		{
			this.removeListener = removeListener;
		}

		@Override
		public void ancestorAdded(AncestorEvent e)
		{
			JComponent component = e.getComponent();
			component.requestFocusInWindow();

			if (removeListener)
				component.removeAncestorListener( this );
		}

		@Override
		public void ancestorMoved(AncestorEvent e) {}

		@Override
		public void ancestorRemoved(AncestorEvent e) {}
	}

	public GenerateHibernateMapping(final Shell shell2, final String path) {
		
		try {
			
			shell = shell2;
			
			String[] dbs = null;
	
			try {
				dbs = Tools.getDBs();
			} catch (Exception e) {
				e.printStackTrace();
				return;
			}
	
			if (dbs == null || dbs.length == 0) {
				MessageDialog.openError(shell, "Error 1", "Couldn't find any databases, go sure your AS400 driver does exist and read the plugin documentation!");
				return;
			}
	
			String db = "";
			//(String) JOptionPane.showInputDialog(Activator.frame, "Which Database?", "Select a Database", JOptionPane.PLAIN_MESSAGE, null, dbs, "GEISDTT");
	
			{
				final DefaultListModel<String> source = new DefaultListModel<String>();
				Stream.of(dbs).forEach(source::addElement);
				final FilteredListModel filteredListModel = new FilteredListModel(source);
				final JList<String> list = new JList<String>(filteredListModel);
				final JScrollPane panel = new JScrollPane(list);
				final JTextField filter = new JTextField();
				filter.addAncestorListener(new RequestFocusListener());
				filteredListModel.setFilter(new FilteredListModel.Filter() {
					@Override
					public boolean accept(final Object element) {
						return filter.getText().isEmpty() || element.toString().toUpperCase().startsWith(filter.getText().toUpperCase());
					}
			    });
				final JPanel pane = new JPanel();
				filter.addActionListener(e -> {
					list.requestFocusInWindow();
					final Robot robot;
					try {
						robot = new Robot();
						robot.keyPress(KeyEvent.VK_ENTER); 
					} catch (AWTException e1) {
						e1.printStackTrace();
					} 
				});
				filter.addKeyListener(new KeyAdapter() {
					@Override
					public void keyPressed(KeyEvent e) {
						if (e.getKeyCode() == KeyEvent.VK_DOWN) {
							int lastSelectedIndex = list.getSelectedIndex();
							if (lastSelectedIndex != list.getModel().getSize()) {
								list.setSelectedIndex(++lastSelectedIndex);
								list.ensureIndexIsVisible(lastSelectedIndex);
							}
						} else if (e.getKeyCode() == KeyEvent.VK_UP) {
							int lastSelectedIndex = list.getSelectedIndex();
							if (lastSelectedIndex != 0) {
								list.setSelectedIndex(--lastSelectedIndex);
								list.ensureIndexIsVisible(lastSelectedIndex);
							}
						} 
					}
				});
				filter.getDocument().addDocumentListener(new DocumentListener() {
					
					@Override
					public void removeUpdate(final DocumentEvent e) {
						filteredListModel.doFilter();
						panel.getVerticalScrollBar().setValue(0);
						list.setSelectedIndex(0);
					}
					
					@Override
					public void insertUpdate(final DocumentEvent e) {
						filteredListModel.doFilter();
						panel.getVerticalScrollBar().setValue(0);
						list.setSelectedIndex(0);
					}
					
					@Override
					public void changedUpdate(final DocumentEvent e) {
						filteredListModel.doFilter();
						panel.getVerticalScrollBar().setValue(0);
						list.setSelectedIndex(0);
					}
				});
				list.addMouseListener(new MouseAdapter() {
				    @Override
					public void mouseClicked(MouseEvent evt) {
				        @SuppressWarnings("unchecked")
				        final JList<String> list = (JList<String>) evt.getSource();
				        if (evt.getClickCount() == 2) {
				            int index = list.locationToIndex(evt.getPoint());
				            list.setSelectedIndex(index);
				            list.requestFocusInWindow();
							final Robot robot;
							try {
								robot = new Robot();
								robot.keyPress(KeyEvent.VK_ENTER); 
							} catch (final AWTException e1) {
								e1.printStackTrace();
							}
				        }
				    }
				});
				list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
				list.setCellRenderer(new MyListCellThing());
				list.setBorder(BorderFactory.createEmptyBorder ( 5, 5, 5, 5 ) );
				list.addAncestorListener(new AncestorListener() {
					
					@Override
					public void ancestorRemoved(final AncestorEvent event) {
					}
					
					@Override
					public void ancestorMoved(final AncestorEvent event) {
					}
					
					@Override
					public void ancestorAdded(final AncestorEvent event) {
						list.requestFocusInWindow();
						list.setSelectedIndex(0);
					}
				});
				pane.setLayout(new BorderLayout());
				pane.add(panel, BorderLayout.CENTER);
				
				pane.add(filter, BorderLayout.PAGE_END);
				if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog(Activator.frame, pane, "Choose your Database from GEISDB01", JOptionPane.OK_CANCEL_OPTION)) {
					return;
				}
				db = list.getModel().getElementAt(list.getSelectedIndex());
			}
			
			
			dbs = null;
	
			if (db != null && !db.trim().isEmpty()) {
				db = db.substring(0, db.indexOf(" - "));
				final String[] tables = Tools.getTables(db);
	
				if (tables == null || tables.length == 0) {
					JOptionPane.showMessageDialog(Activator.frame, "Couldn't find any table!");
					return;
				}
				
				final DefaultListModel<String> source = new DefaultListModel<String>();
				Stream.of(tables).forEach(source::addElement);
				final FilteredListModel filteredListModel = new FilteredListModel(source);
				final JList<String> list = new JList<String>(filteredListModel);
				final JScrollPane panel = new JScrollPane(list);
				final JTextField filter = new JTextField();
				filter.addAncestorListener(new RequestFocusListener());
				filteredListModel.setFilter(new FilteredListModel.Filter() {
					@Override
					public boolean accept(final Object element) {
						return filter.getText().isEmpty() || element.toString().toUpperCase().startsWith(filter.getText().toUpperCase());
					}
			    });
				final JPanel pane = new JPanel();
				filter.addActionListener(e -> {
					list.requestFocusInWindow();
					final Robot robot;
					try {
						robot = new Robot();
						robot.keyPress(KeyEvent.VK_ENTER); 
					} catch (final AWTException e1) {
						e1.printStackTrace();
					}
				});
				filter.getDocument().addDocumentListener(new DocumentListener() {
					
					@Override
					public void removeUpdate(final DocumentEvent e) {
						filteredListModel.doFilter();
						panel.getVerticalScrollBar().setValue(0);
						list.setSelectedIndex(0);
					}
					
					@Override
					public void insertUpdate(final DocumentEvent e) {
						filteredListModel.doFilter();
						panel.getVerticalScrollBar().setValue(0);
						list.setSelectedIndex(0);
					}
					
					@Override
					public void changedUpdate(final DocumentEvent e) {
						filteredListModel.doFilter();
						panel.getVerticalScrollBar().setValue(0);
						list.setSelectedIndex(0);
					}
				});
				filter.addKeyListener(new KeyAdapter() {

					@Override
					public void keyPressed(final KeyEvent e) {
						if (e.getKeyCode() == KeyEvent.VK_DOWN) {
							int lastSelectedIndex = list.getSelectedIndex();
							if (lastSelectedIndex != list.getModel().getSize()) {
								list.setSelectedIndex(++lastSelectedIndex);
								list.ensureIndexIsVisible(lastSelectedIndex);
							}
						} else if (e.getKeyCode() == KeyEvent.VK_UP) {
							int lastSelectedIndex = list.getSelectedIndex();
							if (lastSelectedIndex != 0) {
								list.setSelectedIndex(--lastSelectedIndex);
								list.ensureIndexIsVisible(lastSelectedIndex);
							}
						} 
					}
				});
				list.addMouseListener(new MouseAdapter() {
				    @Override
					public void mouseClicked(final MouseEvent evt) {
				        @SuppressWarnings("unchecked")
				        final JList<String> list = (JList<String>) evt.getSource();
				        if (evt.getClickCount() == 2) {
				            int index = list.locationToIndex(evt.getPoint());
				            list.setSelectedIndex(index);
				            list.requestFocusInWindow();
							final Robot robot;
							try {
								robot = new Robot();
								robot.keyPress(KeyEvent.VK_ENTER); 
							} catch (AWTException e1) {
								e1.printStackTrace();
							}
				        }
				    }
				});
				list.setCellRenderer(new MyListCellThing());
				list.setBorder(BorderFactory.createEmptyBorder ( 5, 5, 5, 5 ) );
				list.addAncestorListener(new AncestorListener() {
					
					@Override
					public void ancestorRemoved(final AncestorEvent event) {
					}
					
					@Override
					public void ancestorMoved(final AncestorEvent event) {
					}
					
					@Override
					public void ancestorAdded(final AncestorEvent event) {
						list.requestFocusInWindow();
						list.setSelectedIndex(0);
					}
				});
				pane.setLayout(new BorderLayout());
				pane.add(panel, BorderLayout.CENTER);
				
				pane.add(filter, BorderLayout.PAGE_END);
				
				if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog(Activator.frame, pane, "Choose your table(s) from GEISDB01." + db, JOptionPane.YES_NO_OPTION)) {
					return;
				}
				String currentTable = null;
				
				int[] selectedIndexes = list.getSelectedIndices();
				if (selectedIndexes == null || selectedIndexes.length == 0) {
					return;
				}
				
				int n;
				if ((path.contains("\\geis_shared\\") || path.contains("\\geis_database\\") || path.contains("\\geis_database_entw\\") || path.contains("\\ServerSocked_MC9090\\")  || path.contains("\\ServerSocked_MC9090_TEST\\")) && path.contains("\\src\\")) {
					n = 1;
				} else if ((path.contains("\\argus_page\\") || path.contains("\\argus_page_entw\\") || path.contains("\\gcc2\\") || path.contains("\\gcc2_entw\\") || path.contains("\\geiswebportal\\") || path.contains("\\geiswebportal_entw\\")) && path.contains("\\src\\")) {
					n = 0;
				} else {
					Object[] options = { "XML + PoJo", "PoJo with Annotations", "Cancel" };
					n = JOptionPane.showOptionDialog(Activator.frame, "Choose the output format of your mappings.", "Output format", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options, options[0]);
					options = null;
					if (n == -1 || n == 2) {
						return;
					}
				}
				
				for (final int currentSelectedIndex : selectedIndexes) {
					currentTable = list.getModel().getElementAt(currentSelectedIndex).trim().toUpperCase();
					currentTable = currentTable.substring(0, currentTable.indexOf(" -"));
					String tableHeading = list.getModel().getElementAt(currentSelectedIndex).trim().substring(list.getModel().getElementAt(currentSelectedIndex).trim().indexOf(" - ") + 3);
					switch (n) {
						case 0:
							try {
								String resultXMLString = convert(currentTable, db, path + '\\' + currentTable.toUpperCase() + '\\' + Character.toUpperCase(currentTable.charAt(0)) + currentTable.substring(1, currentTable.length()).toLowerCase() + ".java");
								final String outputFile = path + '\\' + currentTable.toUpperCase() + '\\' + Character.toUpperCase(currentTable.charAt(0)) + currentTable.substring(1, currentTable.length()).toLowerCase() + ".hbm.xml";
								Tools.write(outputFile, resultXMLString);
								createPoJo(shell, outputFile, db, currentTable, tableHeading);
							} catch (final IOException e) {
								e.printStackTrace();
							}
							break;
						case 1: {
								String resultXMLString = convert(currentTable, db, path + '\\' + currentTable.toUpperCase() + '\\' + Character.toUpperCase(currentTable.charAt(0)) + currentTable.substring(1, currentTable.length()).toLowerCase() + ".java");
								if (tableHeading.endsWith(" -")) {
									tableHeading = tableHeading.substring(0, tableHeading.length() - 2);
								}
								createOutput(currentTable, db, resultXMLString, path + '\\' + currentTable.toUpperCase() + '\\' + Character.toUpperCase(currentTable.charAt(0)) + currentTable.substring(1, currentTable.length()).toLowerCase() + ".java", tableHeading);
								
								if ((path.contains("\\GeisPlugin\\") || path.contains("\\geis_shared\\") || path.contains("\\geis_database\\") || path.contains("\\geis_database_entw\\")) && path.contains("\\src\\")) {
									try {
										final File cfg_xml = new File(path.substring(0, path.indexOf("src")+4) + "META-INF\\" + db + ".cfg.xml");
										if (cfg_xml.exists()) {
											try {
												String inputXML = Tools.readUTF8(cfg_xml.toString());
												final String mappingClass = path.substring(path.indexOf("src")+4).replace('\\', '.') + '.' + currentTable.toUpperCase() + '.' + Character.toUpperCase(currentTable.charAt(0)) + currentTable.substring(1, currentTable.length()).toLowerCase();
												if (!inputXML.contains(mappingClass)) {
													inputXML = inputXML.replace("</session-factory>", "\t<mapping class=\"" + mappingClass + "\"/>\n\t</session-factory>");
													Tools.writeUTF8withFolderCreation(cfg_xml.toString(), inputXML);
												}
											} catch (final Exception e) {
												e.printStackTrace();
											}
										} else {
											final File cfg_mvn_xml = new File(path.substring(0, path.indexOf("\\src\\main\\java\\") + 9) + "\\resources\\META-INF\\" + db + ".cfg.xml");
											final String mappingClass = path.substring(path.indexOf("\\src\\main\\java\\") + 15).replace('\\', '.') + '.' + currentTable.toUpperCase() + '.' + Character.toUpperCase(currentTable.charAt(0)) + currentTable.substring(1, currentTable.length()).toLowerCase();
											if (cfg_mvn_xml.exists()) {
												try {
													String inputXML = Tools.readUTF8(cfg_mvn_xml.toString());
													if (!inputXML.contains(mappingClass)) {
														inputXML = inputXML.replace("</session-factory>", "\t<mapping class=\"" + mappingClass + "\"/>\n\t</session-factory>");
														Tools.writeUTF8withFolderCreation(cfg_mvn_xml.toString(), inputXML);
													}
												} catch (final Exception e) {
													e.printStackTrace();
												}
											} 
										}
										
									} catch (final Exception e) {
										if (Platform.isRunning() && shell != null) {
											MessageDialog.openError(shell, "Fehler", e.getClass() + " - " + e.getMessage() + "\nPlease go sure that you are using the latest plugin version!");
										} else {
											e.printStackTrace();
										}
									}
								}
								break;
							}
					}
				}
			} 
		} finally {
			try {
				if (Tools.con != null && !Tools.con.isClosed()) {
					try {
						Tools.con.rollback();
						Tools.con.close();
					} catch (final SQLException e) {
					}
					Tools.con = null;
				}
			} catch (final SQLException e) {
				e.printStackTrace();
			}
		}
	}

	private void createPoJo(final Shell shell, final String firstElement, String DB, String table, String tableHeading) {
		final Map<String, String> columnHeadings = getColumnHeadings(DB, table);
		sql_type = "";
		buf = "";
		try {
			String paggageStr = "";
			try {
				paggageStr = firstElement.substring(firstElement.lastIndexOf("src\\") + 4, firstElement.length());
				paggageStr = paggageStr.replace('\\', '.');
				paggageStr = paggageStr.split(".hbm.xml")[0];
				paggageStr = "package " + paggageStr.substring(0, paggageStr.lastIndexOf('.')) + ';';
			} catch (final Exception e) {
				MessageDialog.openInformation(shell, "", "patsch");
			}

			String filepath = firstElement;
			filepath = filepath.replace("/", "\\");
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();

			dbFactory.setValidating(false);
			dbFactory.setNamespaceAware(true);
			dbFactory.setFeature("http://xml.org/sax/features/namespaces", false);
			dbFactory.setFeature("http://xml.org/sax/features/validation", false);
			dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
			dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
			
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			dBuilder.toString();
			//System.out.println(filepath);
			Document doc = dBuilder.parse(filepath);
			doc.getDocumentElement().normalize();
			String className = doc.getElementsByTagName("class").item(0).getAttributes().getNamedItem("table").getNodeValue();
			className = className.substring(0, 1).toUpperCase() + className.substring(1).toLowerCase();
			String outputFilePath = filepath.subSequence(0, filepath.lastIndexOf('\\')) + "\\" + className + ".java";
			if (new File(outputFilePath).exists() && Platform.isRunning() && shell != null) {
				if (!MessageDialog.openQuestion(shell, "File existing", "PoJo is already existing! Do you want to overwrite it?")) {
					return;
				}
			}

			buf += (paggageStr + "\n\n" + "import java.util.Date;\n" + "import java.io.Serializable;\n" + "import java.math.BigDecimal;\n"  + "import java.math.BigInteger;\n\n" + "/**" + (tableHeading != null && !tableHeading.trim().isEmpty() ? "\n * " + tableHeading : "") + "\n * DE: \n *\n * EN: \n * \n * \n * Program changes\n * **************************************************************************************\n * Date\t\t\t* Ticket\t* KonzFirm\t* Responsible\t* programmer    *\n * Change\t\t\t\t\t\t\t\t\t\t*\n * **************************************************************************************\n *\n * @author " + System.getProperty("user.name") + "\n * @version 1.0\n *\n */" + "\n\npublic class " + className + " implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n");

			NodeList nodes = doc.getElementsByTagName("property");
			try {
				String id = doc.getElementsByTagName("id").item(0).getAttributes().getNamedItem("name").getNodeValue();
				
				if (columnHeadings.containsKey(id.toUpperCase())) {
					buf += "\n\t" + "/** " + columnHeadings.get(id.toUpperCase()) + "*/";
				}
				
				if (keyType.get(id.toUpperCase()).equals("integer")) {
					buf += ("\n\tprivate Integer " + id + " = null;");
					if (columnHeadings.containsKey(id.toUpperCase())) {
						buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
					}
					buf += ("\n\tpublic Integer get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "() { return " + id + "; }");
					if (columnHeadings.containsKey(id.toUpperCase())) {
						buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
					}
					buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final Integer " + id + ") { this." + id + " = " + id + "; }\n");
				} else {
					int size = keyLength.get(id.toUpperCase());
					if (size > 18) {
						buf += ("\n\tprivate BigDecimal " + id + " = null;");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic BigDecimal get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "() { return " + id + "; }");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final BigDecimal " + id + ") { this." + id + " = " + id + "; }\n");
					} else if (size > 9) {
						buf += ("\n\tprivate Long " + id + " = null;");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic Long get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "() { return " + id + "; }");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final Long " + id + ") { this." + id + " = " + id + "; }\n");
					} else {
						buf += ("\n\tprivate Integer " + id + " = null;");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic Integer get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "() { return " + id + "; }");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final Integer " + id + ") { this." + id + " = " + id + "; }\n");
					}
				}
				
			} catch (final Exception e) {
			}
			
			NodeList compID = doc.getElementsByTagName("key-property");
			if (compID != null && compID.getLength() > 0) {
				createMappingNoAnnotations(compID, shell, columnHeadings);
			}

			createMappingNoAnnotations(nodes, shell, columnHeadings);


			buf += "\n}";
			if (!buf.contains("public BigDecimal ")) {
				buf = buf.replace("import java.math.BigDecimal;\n", "");
			}
			if (!buf.contains("public BigInteger ")) {
				buf = buf.replace("import java.math.BigInteger;\n", "");
			}
			if (!buf.contains("public Date ")) {
				buf = buf.replace("import java.util.Date;\n", "");
			}
			Tools.write(outputFilePath, buf);
			try {
				Tools.getCurrentSelectedProject().refreshLocal(IResource.DEPTH_INFINITE, null);
			} catch (final Exception e) {
			}
		} catch (final Exception e) {
			if (Platform.isRunning() && shell != null) {
				MessageDialog.openError(shell, "Fehler", "Fehlernummer " + "!\n " + e.getMessage() + "Please go sure that you are using the latest plugin version!\n\nSQL Type:" + sql_type);
			} else {
				e.printStackTrace();
			}
		}
	}

	private void createMappingNoAnnotations(final NodeList nodes, final Shell shell, final Map<String, String> columnHeadings) {
		for (int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				String type = "";
				String name = node.getAttributes().getNamedItem("name").getNodeValue();
				String getSetName = Character.toUpperCase(name.charAt(0)) + name.toLowerCase().substring(1, name.length());
				if (columnHeadings.containsKey(name.toUpperCase())) {
					buf += "\n\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/";
				}
				try {
					sql_type = ((Element) node).getElementsByTagName("column").item(0).getAttributes().getNamedItem("sql-type").getNodeValue();
				} catch (Exception e) {
					sql_type = node.getAttributes().getNamedItem("type").getNodeValue().trim();
					if (sql_type.equals("string")) {
						sql_type = "character";
						sql_type += "(" + node.getAttributes().getNamedItem("length").getNodeValue().trim() + ")";
					}
				}

				if (sql_type.startsWith("decimal")) {
					sql_type = sql_type.replaceAll("decimal", "numeric");
					sql_type = sql_type.substring(0, sql_type.length() - 1) + ",0)";
				}

				if (sql_type.startsWith("character") || sql_type.startsWith("varchar") || sql_type.startsWith("nchar") || sql_type.startsWith("clob")) {
					buf += ("\n\tprivate String " + name + " = \"\";");
					type = "String";
				} else {

					if (sql_type.startsWith("numeric")) {
						int nachKommaStellen = Integer.valueOf(sql_type.substring(sql_type.lastIndexOf(',') + 1, sql_type.length() - 1));
						int size = Integer.valueOf(sql_type.substring(sql_type.indexOf('(') + 1, sql_type.lastIndexOf(',')));

						if (nachKommaStellen == 0) {
							if (size > 18) {
								buf += ("\n\tprivate BigDecimal " + name + " = BigDecimal.ZERO;");
								type = "BigDecimal";
							} else if (size > 9) {
								buf += ("\n\tprivate Long " + name + " = 0L;");
								type = "Long";
							} else {
								buf += ("\n\tprivate Integer " + name + " = 0;");
								type = "Integer";
							}
						} else {
							buf += ("\n\tprivate Double " + name + " = 0.0D;");
							type = "Double";

						}
					} else
						if (sql_type.startsWith("short")) {
							buf += ("\n\tprivate Short " + name + " = 0;");
							type = "Short";
						} else
							if (sql_type.startsWith("date") || sql_type.startsWith("timestamp") || sql_type.startsWith("time")) {
								buf += ("\n\tprivate Date " + name + " = null;");
								type = "Date";
							} else if (sql_type.startsWith("integer")) {
								buf += ("\n\tprivate Integer " + name + " = 0;");
								type = "Integer";
							} else {
								MessageDialog.openInformation(shell, "Info", "Unknown type:\n" + sql_type);
								continue;
							}
				}
				if (columnHeadings.containsKey(name.toUpperCase())) {
					buf += "\n\t" + "/** get \"" + columnHeadings.get(name.toUpperCase()) + "\"*/";
				}
				buf += ("\n\tpublic " + type + " get" + getSetName + "() { return " + name + "; }");
				if (columnHeadings.containsKey(name.toUpperCase())) {
					buf += "\n\t" + "/** set \"" + columnHeadings.get(name.toUpperCase()) + "\"*/";
				}
				buf += ("\n\tpublic void set" + getSetName + "(final " + type + " " + name + ") { this." + name + " = " + name + "; }\n");
			}
		}
	}

	//private final static String url = "jdbc:as400://as400;metadata source=0";

	private String buf = "";
	private String sql_type = "";
	private List<String> primKeys = new ArrayList<String>();
	private Map<String, Integer> keyLength = new HashMap<String, Integer>();
	private Map<String, String> keyType = new HashMap<String, String>();

	private List<String> getPrimaryKeys(final String db, final String table) {
		StringBuilder sql = new StringBuilder()
		.append(" select ")
		.append("       RTRIM(c.column_name)")
		.append("  from qsys2.syscolumns   c")
		.append("  join qsys2.systables    t")
		.append("    on c.table_schema = t.table_schema")
		.append("   and c.table_name   = t.table_name")
		.append("  left outer join sysibm.sqlstatistics k")
		.append("    on c.table_schema = k.table_schem")
		.append("   and c.table_name   = k.table_name")
		.append("   and c.table_name   = k.index_name")
		.append("   and c.column_name  = k.column_name")
		.append(" where c.table_schema = '").append(db).append("'")
		.append("   and c.table_name   = '").append(table).append("'")
		.append("   and  k.ordinal_position IS NOT NULL")
		.append(" ORDER BY  k.ordinal_position");
		/**
		.append(" SELECT")
		.append("	RTRIM(DBKFLD)")
		.append(" FROM")
		.append("	QSYS.QADBXREF")
		.append(" LEFT JOIN")
		.append("	QSYS.QADBKFLD")
		.append("	on DBXFIL = DBKFIL and DBXLIB = DBKLIB")
		.append(" WHERE")
		.append("	DBXLIB = '").append(db).append("'")
		.append("	and DBXLFI='").append(table).append("'")
		.append(" ORDER BY DBKPOS");
		**/
		
		Connection jdbc = null;
		
		try {
			jdbc = Tools.getConnection();
			try (Statement stmt = jdbc.createStatement();
					ResultSet rs = stmt.executeQuery(sql.toString());) {
				final List<String> result = new ArrayList<String>();
				while (rs.next()) {
					result.add(rs.getString(1));
				}
				return result;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return Collections.emptyList();
	}
	
	public Map<String, String> getColumnDefault(final String db, final String table) {
		Connection jdbc = null;
		Statement stmt = null;
		ResultSet rs = null;

		try {
			jdbc = Tools.getConnection();
			stmt = jdbc.createStatement();
			rs = stmt.executeQuery("SELECT RTRIM(a.COLUMN_NAME), RTRIM(b.COLUMN_DEFAULT) FROM qsys2.SYSCOLUMNS a LEFT JOIN qsys2.columns b ON a.TBNAME=b.TABLE_NAME AND a.TABLE_SCHEMA = b.TABLE_SCHEMA AND a.COLUMN_NAME = b.COLUMN_NAME WHERE a.TBNAME = '" + table + "' AND a.TABLE_SCHEMA = '" + db + "'  AND b.COLUMN_DEFAULT IS NOT NULL AND b.COLUMN_DEFAULT != ''''''");
			
			final Map<String, String> descriptions = new HashMap<String, String>();

			while (rs.next()) {
				descriptions.put(rs.getString(1).toUpperCase(), rs.getString(2));
			}
			
			return descriptions;
		} catch (final Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (final Exception e) {
					e.printStackTrace();
				}
				rs = null;
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (final Exception e) {
					e.printStackTrace();
				}
				stmt = null;
			}
		}
		return Collections.emptyMap();
	}
	
	public Map<String, String> getColumnHeadings(final String db, final String table) {
		Connection jdbc = null;
		Statement stmt = null;
		ResultSet rs = null;

		try {
			jdbc = Tools.getConnection();
			stmt = jdbc.createStatement();
			rs = stmt.executeQuery("SELECT RTRIM(COLUMN_NAME), RTRIM(COLUMN_HEADING) FROM qsys2.SYSCOLUMNS WHERE TBNAME = '" + table + "' AND TABLE_SCHEMA = '" + db + "' AND COLUMN_HEADING != '' ORDER BY ORDINAL_POSITION ASC");
			
			final Map<String, String> descriptions = new HashMap<String, String>();

			while (rs.next()) {
				descriptions.put(rs.getString(1).toUpperCase(), rs.getString(2));
			}
			
			return descriptions;
		} catch (final Exception e) {
			e.printStackTrace();
		} finally {
			if (rs != null) {
				try {
					rs.close();
				} catch (final Exception e) {
					e.printStackTrace();
				}
				rs = null;
			}
			if (stmt != null) {
				try {
					stmt.close();
				} catch (final Exception e) {
					e.printStackTrace();
				}
				stmt = null;
			}
		}
		return Collections.emptyMap();
	}
	
	private LinkedHashMap<String, DatabaseTableObjekt> getTable(final String db, final String table) {
		LinkedHashMap<String, DatabaseTableObjekt> tablesMap = new LinkedHashMap<String, DatabaseTableObjekt>();

		Connection jdbc = null;
		try {
			jdbc = Tools.getConnection();
			ResultSet rs = jdbc.getMetaData().getPrimaryKeys(null, db, table);
			while (rs.next()) {
				primKeys.add(rs.getString(4));//"COLUMN_NAME"
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}
		} catch (final Exception e) {
			e.printStackTrace();
		}

		try {
			jdbc = Tools.getConnection();
			Statement stmt = jdbc.createStatement();
			String sql = "SELECT * FROM " + db + '.' + table;
			stmt.setFetchSize(1);
			ResultSet rs = stmt.executeQuery(sql);
			ResultSetMetaData rsmd = rs.getMetaData();
			boolean hasID = false;
			
			for (int i = 1; i < rsmd.getColumnCount() + 1; ++i) {
				boolean ID = false;
				if (i == 1 && rsmd.isSigned(i) && rsmd.isReadOnly(i) && rsmd.isNullable(i) == ResultSetMetaData.columnNoNulls && rsmd.isSearchable(i) && !rsmd.isCaseSensitive(i) && rsmd.getColumnType(i) == 4 && rsmd.getColumnName(i).toUpperCase().contains("ID")) {
					if (!primKeys.contains(rsmd.getColumnTypeName(i))) {
						ID = true;
					}
				}
				//System.out.println(rsmd.getColumnName(i)+ " precision: " + rsmd.getPrecision(i) + " scale: " + rsmd.getScale(i) + " type: " + rsmd.getColumnTypeName(i));
				DatabaseTableObjekt local = new DatabaseTableObjekt(rsmd.getColumnTypeName(i), rsmd.getColumnLabel(i), rsmd.getColumnType(i), rsmd.getScale(i), rsmd.getPrecision(i), ID, rsmd.isNullable(i) == 0, rsmd.getColumnDisplaySize(i));
				//System.out.println(rsmd.getColumnLabel(i) + " " + rsmd.getColumnTypeName(i));
				tablesMap.put(rsmd.getColumnName(i), local);
				keyLength.put(rsmd.getColumnLabel(i), rsmd.getPrecision(i));
				keyType.put(rsmd.getColumnLabel(i), rsmd.getColumnTypeName(i).toLowerCase());
				if (local.isID()) {
					hasID = true;
				}
			}
			
			if (primKeys.isEmpty() && !hasID) {
				primKeys.addAll(getPrimaryKeys(db, table));
				if (primKeys.isEmpty() && !hasID) {
					if (Platform.isRunning()) {
						MessageDialog.openInformation(shell, "Warning", "Please manually modify your mapping file later, no ID field was found in " + db + "." + table);
					} else {
						JOptionPane.showOptionDialog(Activator.frame, "Please manually modify your mapping file later, no ID field was found in "  + db + "." + table, "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.ERROR_MESSAGE, null, null, null);
					}
				}
			}

			if (rs != null) {
				rs.close();
				rs = null;
			}
			if (stmt != null) {
				stmt.close();
				stmt = null;
			}
		} catch (final Exception e) {
			e.printStackTrace();
		}
		return tablesMap;
	}

	private String convert(final String table, final String DB, final String pack) {
		//System.out.println(pack);
		primKeys.clear();
		LinkedHashMap<String, DatabaseTableObjekt> myTable = getTable(DB, table);
		
		final Map<String, String> defaults = getColumnDefault(DB, table);

		String paggageStr = "";
		try {
			if (pack.contains("\\src\\main\\java\\de\\geis\\datenbanken")) {
				paggageStr = pack.substring(pack.lastIndexOf("src\\main\\java\\") + 14, pack.length());
			} else {
				paggageStr = pack.substring(pack.lastIndexOf("src\\") + 4, pack.length());
			}
			paggageStr = paggageStr.replace('\\', '.');
			paggageStr = paggageStr.split(".java")[0];
			paggageStr = paggageStr.substring(0, paggageStr.lastIndexOf('.'));
		} catch (final Exception e) {
			e.printStackTrace();
			if (shell != null) {
				MessageDialog.openInformation(shell, "", "patsch");
			}
		}

		StringBuilder resultString = new StringBuilder();
		resultString.append("<?xml version=\"1.0\"?>\n<!DOCTYPE hibernate-mapping PUBLIC\n        \"-//Hibernate/Hibernate Mapping DTD 3.0//EN\"\n        \"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">\n<hibernate-mapping>\n\t<class name=\"");
		resultString.append(paggageStr);
		resultString.append('.');
		resultString.append(Character.toUpperCase(table.charAt(0)));
		resultString.append(table.substring(1, table.length()).toLowerCase());
		
		resultString.append("\" table=\"");
		resultString.append(table.toUpperCase());
		resultString.append("\">\n");

		if (!primKeys.isEmpty()) {

			if (primKeys.size() > 1) {

				resultString.append("\t\t<composite-id>\n");
				for (String myStr : primKeys) {
					DatabaseTableObjekt currentDBObj = myTable.get(myStr);
					String myStrLower = myStr.toLowerCase();
					resultString.append("\t\t\t<key-property name=\"");
					resultString.append(myStrLower);
					resultString.append("\"><column name=\"");
					resultString.append(myStr);
					resultString.append("\" sql-type=\"");
					String type = currentDBObj.getColumnTypeString().toLowerCase();
					if (type.equals("char")) {
						type = "character";
					} else
						if (type.equals("decimal") || type.equals("bigint")) {
							type = "numeric";
						}
					resultString.append(type);
					resultString.append('(');
					resultString.append(currentDBObj.getPrecision());
					if (type.equals("numeric") || type.toLowerCase().contains("date")) {
						resultString.append(',');
						resultString.append(currentDBObj.getScale());
					}
					resultString.append(")\"/></key-property>\n");
				}
				resultString.append("\t\t</composite-id>\n");
			} else {
				DatabaseTableObjekt currentDBObj = myTable.get(primKeys.get(0));
				if (currentDBObj.getColumnTypeString().toLowerCase().equals("bigint") || (currentDBObj.getColumnTypeString().toLowerCase().equals("numeric") && currentDBObj.getPrecision() > 18)) {
					resultString.append("\t\t\n\t\t<id name=\"");
					resultString.append(primKeys.get(0).toLowerCase());
					resultString.append("\" type=\"java.math.BigDecimal\">\n\t\t\t<column name=\"");
					resultString.append(primKeys.get(0));
					resultString.append("\"/>\n\t\t\t<generator class=\"de.geis.datenbanken.toolbox.bigdecimalid.ExtendedIdentityGenerator\"/>\n\t\t</id>\n\t\t\n");
					
				} else {
					resultString.append("\t\t\n\t\t<id name=\"");
					resultString.append(primKeys.get(0).toLowerCase());
					resultString.append("\">\n\t\t\t<column name=\"");
					resultString.append(primKeys.get(0));
					resultString.append("\"/>\n\t\t\t<generator class=\"native\"/>\n\t\t</id>\n\t\t\n");
				}
			}
		}

		for (final String local : myTable.keySet()) {

			if (primKeys.contains(local))
				continue;

			DatabaseTableObjekt currentDBObj = myTable.get(local);
			String localLower = local.toLowerCase();

			if (currentDBObj.isID() && primKeys.isEmpty()) {
				resultString.append("\t\t\n\t\t<id name=\"");
				resultString.append(localLower);
				resultString.append("\">\n\t\t\t<column name=\"");
				resultString.append(local);
				resultString.append("\"/>\n\t\t\t<generator class=\"native\"/>\n\t\t</id>\n\t\t\n");
				continue;
			}

			resultString.append("\t\t<property name=\"");
			resultString.append(localLower);
			resultString.append("\"");
			
			if (defaults.containsKey(local.toUpperCase())) {
				switch (defaults.get(local.toUpperCase())) {
					case "USER":
					case "CURRENT_TIMESTAMP":
						resultString.append(" insert=\"false\" update=\"false\"");
						break;
				}
			}
			
			resultString.append("><column name=\"");
			resultString.append(local);
			resultString.append("\" sql-type=\"");

			String type = currentDBObj.getColumnTypeString().toLowerCase();

			if (type.equals("char")) {
				type = "character";
			} else if (type.equals("decimal") || type.equals("bigint")) {
				type = "numeric";
			} else if (type.equals("smallint")) {
				type = "short";
			} 
			
			if (type.equals("date") || type.equals("timestamp") || type.equals("time") || type.equals("integer")) {
				resultString.append(type);
				resultString.append("\"");
			} else {
				resultString.append(type);
				resultString.append('(');
				resultString.append(currentDBObj.getPrecision());

				if (type.equals("numeric")) {
					resultString.append(',');
					resultString.append(currentDBObj.getScale());
				}
				resultString.append(")\"");
			}
			
			if (currentDBObj.isNotnullable()) {
				resultString.append(" not-null=\"true\"");
			}
			
			resultString.append("/></property>\n");
		}
		resultString.append("\t</class>\n</hibernate-mapping>");

		return resultString.toString();
	}

	@SuppressWarnings("static-access")
	public static void main(final String[] args) {
		//Um Design beim Ausführen über Main-Methode zu laden
		Activator.frame.isDefaultLookAndFeelDecorated();
//		new GenerateHibernateMapping(null, "C:\\projects\\GeisPlugin\\src\\main\\java\\de\\geis\\datenbanken");
		
		new GenerateHibernateMapping(null, FileSystemView.getFileSystemView().getHomeDirectory().toString());
		System.exit(0);
	}

	private void createOutput(final String table, final String DB, final String xml, final String outputFilePath, final String tableHeading) {
		sql_type = "";
		buf = "";
		final Map<String, String> columnHeadings = getColumnHeadings(DB, table);
		try {

			String packageStr = "";
			try {
				if (outputFilePath.contains("\\src\\main\\java\\de\\geis\\datenbanken")) {
					packageStr = outputFilePath.substring(outputFilePath.lastIndexOf("src\\main\\java\\") + 14, outputFilePath.length());
				} else {
					packageStr = outputFilePath.substring(outputFilePath.lastIndexOf("src\\") + 4, outputFilePath.length());
				}
				packageStr = packageStr.replace('\\', '.');
				packageStr = packageStr.split(".java")[0];
				packageStr = "package " + packageStr.substring(0, packageStr.lastIndexOf('.')) + ';';
			} catch (final Exception e) {
				e.printStackTrace();
				if (shell != null) {
					MessageDialog.openInformation(shell, "Error 2", e.getMessage());
				}
			}

			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			
			dbFactory.setValidating(false);
			dbFactory.setNamespaceAware(true);
			dbFactory.setFeature("http://xml.org/sax/features/namespaces", false);
			dbFactory.setFeature("http://xml.org/sax/features/validation", false);
			dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
			dbFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
			
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.parse(new InputSource(new StringReader(xml)));
			doc.getDocumentElement().normalize();
			String className = doc.getElementsByTagName("class").item(0).getAttributes().getNamedItem("table").getNodeValue();
			className = className.substring(0, 1).toUpperCase() + className.substring(1).toLowerCase();

			buf += (packageStr + "\n\n" + "import java.util.Date;\n" + "import java.io.Serializable;\nimport javax.persistence.*;\n\nimport org.hibernate.annotations.Type;\n\n" + "import java.math.BigDecimal;\n\n" + "import java.math.BigInteger;\n\n" + "/**" + (tableHeading != null && !tableHeading.trim().isEmpty() ? "\n * " + tableHeading : "") + "\n * DE: \n *\n * EN: \n * \n * \n * Program changes\n * **************************************************************************************\n * Date\t\t\t* Ticket\t* KonzFirm\t* Responsible\t* programmer    *\n * Change\t\t\t\t\t\t\t\t\t\t*\n * **************************************************************************************\n *\n * @author " + System.getProperty("user.name") + "\n * @version 1.0\n *\n */" + "\n\n@Entity\n" + "@Table(name=\"" + className.toUpperCase() + "\")\n" + "//@NamedQuery(name=\"" + className + ".findAll\", query=\"SELECT g FROM " + className.toUpperCase() + " g WHERE g.konzPLACEHOLDER=:konzPLACEHOLDER AND g.firmPLACEHOLDER=:firmPLACEHOLDER\")\n" + "public class " + className + " implements Serializable {\n\n\tprivate static final long serialVersionUID = 1L;\n");

			NodeList nodes = doc.getElementsByTagName("property");
			try {
				String id = doc.getElementsByTagName("id").item(0).getAttributes().getNamedItem("name").getNodeValue();
				try {
					if (columnHeadings.containsKey(id.toUpperCase())) {
						buf += "\n\t" + "/** " + columnHeadings.get(id.toUpperCase()) + "*/";
					}
					buf += "\n\t@Id\n\t@GeneratedValue(strategy=GenerationType.IDENTITY)\n\t@Column(unique=true, nullable=false)\n\t";
					if (keyType.get(id.toUpperCase()).equals("integer")) {
						buf += "private Integer " + id + " = null;";
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic Integer get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()).toLowerCase() + "() { return " + id + "; }");
						if (columnHeadings.containsKey(id.toUpperCase())) {
							buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
						}
						buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final Integer " + id + ") { this." + id + " = " + id + "; }\n");
					} else {
						int size = keyLength.get(id.toUpperCase());
						if (size > 18) {
							buf += "private BigDecimal " + id + " = null;";
							if (columnHeadings.containsKey(id.toUpperCase())) {
								buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
							}
							buf += ("\n\tpublic BigDecimal get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()).toLowerCase() + "() { return " + id + "; }");
							if (columnHeadings.containsKey(id.toUpperCase())) {
								buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
							}
							buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final BigDecimal " + id + ") { this." + id + " = " + id + "; }\n");
						} else if (size > 9) {
							buf += "private Long " + id + " = null;";
							if (columnHeadings.containsKey(id.toUpperCase())) {
								buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
							}
							buf += ("\n\tpublic Long get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()).toLowerCase() + "() { return " + id + "; }");
							if (columnHeadings.containsKey(id.toUpperCase())) {
								buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
							}
							buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final Long " + id + ") { this." + id + " = " + id + "; }\n");
						} else {
							buf += "private Integer " + id + " = null;";
							if (columnHeadings.containsKey(id.toUpperCase())) {
								buf += "\n\t" + "/** get \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
							}
							buf += ("\n\tpublic Integer get" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()).toLowerCase() + "() { return " + id + "; }");
							if (columnHeadings.containsKey(id.toUpperCase())) {
								buf += "\n\t" + "/** set \"" + columnHeadings.get(id.toUpperCase()) + "\"*/";
							}
							buf += ("\n\tpublic void set" + Character.toUpperCase(id.charAt(0)) + id.substring(1, id.length()) + "(final Integer " + id + ") { this." + id + " = " + id + "; }\n");
						}
					}
					
				} catch (final Exception e) {
					e.printStackTrace();
					if (shell != null) {
						MessageDialog.openInformation(shell, "Error 3", e.getMessage());
					}
				}
			} catch (Exception e) {
				
			}
			
			Map<String, String> defaults = getColumnDefault(DB, table);
			
			NodeList compID = doc.getElementsByTagName("key-property");
			if (compID != null && compID.getLength() > 0) {
				createMappingWithAnnotations(compID, true, columnHeadings, defaults);
			}

			createMappingWithAnnotations(nodes, false, columnHeadings, defaults);


			if (buf.contains(" g WHERE g.konzPLACEHOLDER=:konzPLACEHOLDER AND g.firmPLACEHOLDER=:firmPLACEHOLDER")) {
				buf = buf.replaceAll(" g WHERE g.konzPLACEHOLDER=:konzPLACEHOLDER AND g.firmPLACEHOLDER=:firmPLACEHOLDER", "");
			}

			buf += "\n}";
			if (!buf.contains("public BigDecimal ")) {
				buf = buf.replace("import java.math.BigDecimal;\n", "");
			}
			if (!buf.contains("public BigInteger ")) {
				buf = buf.replace("import java.math.BigInteger;\n", "");
			}
			if (!buf.contains("public Date ")) {
				buf = buf.replace("import java.util.Date;\n", "");
				buf = buf.replace("import org.hibernate.annotations.Type;\n\n", "");
			}
			Tools.writeUTF8withFolderCreation(outputFilePath, buf);
		} catch (final Exception e) {
			e.printStackTrace();
			if (shell != null) {
				MessageDialog.openInformation(shell, "Error 4", e.getMessage());
			}
		}
	}
	
	private void createMappingWithAnnotations(final NodeList nodes, final boolean id, final Map<String, String> columnHeadings, final Map<String, String> defaults) {
		for (int i = 0; i < nodes.getLength(); i++) {
			Node node = nodes.item(i);

			if (node.getNodeType() == Node.ELEMENT_NODE) {
				boolean notNullable = false;
				String type = "";
				String name = node.getAttributes().getNamedItem("name").getNodeValue();
				String getSetName = Character.toUpperCase(name.charAt(0)) + name.toLowerCase().substring(1, name.length());
				try {
					sql_type = ((Element) node).getElementsByTagName("column").item(0).getAttributes().getNamedItem("sql-type").getNodeValue();
				} catch (Exception e) {
					sql_type = node.getAttributes().getNamedItem("type").getNodeValue().trim();
					if (sql_type.equals("string")) {
						sql_type = "character";
						sql_type += "(" + node.getAttributes().getNamedItem("length").getNodeValue().trim() + ")";
					}
				}
				try {
					if (((Element) node).getElementsByTagName("column").item(0).getAttributes().getNamedItem("not-null").getNodeValue().equals("true")) {
						notNullable = true;
					}
				} catch (Exception e) {
					
				}
				
				if (sql_type.startsWith("varchar")) {
					sql_type = sql_type.replaceAll("varchar", "character");
				}

				if (sql_type.startsWith("decimal")) {
					sql_type = sql_type.replaceAll("decimal", "numeric");
					sql_type = sql_type.substring(0, sql_type.length() - 1) + ",0)";
				}
				
				if (id) {
					if (columnHeadings.containsKey(name.toUpperCase())) {
						buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
					}
					if (defaults.containsKey(name.toUpperCase())) {
						switch (defaults.get(name.toUpperCase())) {
							case "USER":
							case "CURRENT_TIMESTAMP":
								buf += "\t@Generated(GenerationTime.ALWAYS)\n";
								break;
						}
					}
					buf += ("\n\n\t@Id\n");
				} else {
					buf += ("\n\n");
				}

				if (sql_type.startsWith("integer")) {
					if (!id && columnHeadings.containsKey(name.toUpperCase())) {
						buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
					}
					if (!id && defaults.containsKey(name.toUpperCase())) {
						switch (defaults.get(name.toUpperCase())) {
							case "USER":
							case "CURRENT_TIMESTAMP":
								buf += "\t@Generated(GenerationTime.ALWAYS)\n";
								break;
						}
					}
					if (notNullable) {
						buf += ("\t@Column(nullable = false)");
					} else {
						buf += ("\t@Column");
					}
					buf += ("\n\tprivate Integer " + name + " = 0;");
					type = "Integer";
				} else if (sql_type.startsWith("character") || sql_type.startsWith("nchar") || sql_type.startsWith("graphic") || sql_type.startsWith("clob")) {
					if (name.endsWith("konz")) {
						buf = buf.replaceAll("konzPLACEHOLDER", name);
					}

					else
						if (name.endsWith("firm")) {
							buf = buf.replaceAll("firmPLACEHOLDER", name);
						}
					
					int size = 0;
					if (sql_type.startsWith("character")) {
						size = Integer.valueOf(sql_type.substring(10, sql_type.length() - 1));
					} else if (sql_type.startsWith("graphic")) {
						size = Integer.valueOf(sql_type.substring(8, sql_type.length() - 1));
					} else if (sql_type.startsWith("clob")) {
						size = Integer.valueOf(sql_type.substring(5, sql_type.length() - 1));
					} else {
						size = Integer.valueOf(sql_type.substring(6, sql_type.length() - 1));
					}
					if (!id && columnHeadings.containsKey(name.toUpperCase())) {
						buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
					}
					if (!id && defaults.containsKey(name.toUpperCase())) {
						switch (defaults.get(name.toUpperCase())) {
							case "USER":
							case "CURRENT_TIMESTAMP":
								buf += "\t@Generated(GenerationTime.ALWAYS)\n";
								break;
						}
					}
					if (notNullable) {
						buf += ("\t@Column(length=" + size + ", nullable = false)");
					} else {
						buf += ("\t@Column(length=" + size + ")");
					}
					buf += ("\n\tprivate String " + name + " = \"\";");
					type = "String";
				}

				else {
					if (sql_type.startsWith("numeric")) {
						int nachKommaStellen = Integer.valueOf(sql_type.substring(sql_type.lastIndexOf(',') + 1, sql_type.length() - 1));
						int size = Integer.valueOf(sql_type.substring(sql_type.indexOf('(') + 1, sql_type.lastIndexOf(',')));

						if (nachKommaStellen == 0) {
							if (!id && columnHeadings.containsKey(name.toUpperCase())) {
								buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
							}
							if (!id && defaults.containsKey(name.toUpperCase())) {
								switch (defaults.get(name.toUpperCase())) {
									case "USER":
									case "CURRENT_TIMESTAMP":
										buf += "\t@Generated(GenerationTime.ALWAYS)\n";
										break;
								}
							}
							if (notNullable) {
								buf += ("\t@Column(precision=" + size + ", nullable = false)");
							} else {
								buf += ("\t@Column(precision=" + size + ")");
							}
							if (size > 18) {
								buf += ("\n\tprivate BigDecimal " + name + " = BigDecimal.ZERO;");
								type = "BigDecimal";
							} else if (size > 9) {
								buf += ("\n\tprivate Long " + name + " = 0L;");
								type = "Long";

							} else {
								buf += ("\n\tprivate Integer " + name + " = 0;");
								type = "Integer";
							}
						} else {
							if (!id && columnHeadings.containsKey(name.toUpperCase())) {
								buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
							}
							if (!id && defaults.containsKey(name.toUpperCase())) {
								switch (defaults.get(name.toUpperCase())) {
									case "USER":
									case "CURRENT_TIMESTAMP":
										buf += "\t@Generated(GenerationTime.ALWAYS)\n";
										break;
								}
							}
							if (notNullable) {
								buf += ("\t@Column(precision=" + size + ", scale=" + nachKommaStellen + ", nullable = false)");
							} else {
								buf += ("\t@Column(precision=" + size + ", scale=" + nachKommaStellen + ")");
							}
							buf += ("\n\tprivate Double " + name + " = 0.0D;");
							type = "Double";

						}
					}

					else {

						if (sql_type.startsWith("short")) {
							int size = Integer.valueOf(sql_type.substring(sql_type.indexOf('(') + 1, sql_type.lastIndexOf(')')));
							if (!id && columnHeadings.containsKey(name.toUpperCase())) {
								buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
							}
							if (!id && defaults.containsKey(name.toUpperCase())) {
								switch (defaults.get(name.toUpperCase())) {
									case "USER":
									case "CURRENT_TIMESTAMP":
										buf += "\t@Generated(GenerationTime.ALWAYS)\n";
										break;
								}
							}
							if (notNullable) {
								buf += ("\t@Column(precision=" + size + ", nullable = false)");
							} else {
								buf += ("\t@Column(precision=" + size + ")");
							}
							buf += ("\n\tprivate Short " + name + " = 0;");
							type = "Short";
						} else
							if (!id && columnHeadings.containsKey(name.toUpperCase())) {
								buf += "\t" + "/** " + columnHeadings.get(name.toUpperCase()) + "*/\n";
							}
							if (!id && defaults.containsKey(name.toUpperCase())) {
								switch (defaults.get(name.toUpperCase())) {
									case "USER":
									case "CURRENT_TIMESTAMP":
										buf += "\t@Generated(GenerationTime.ALWAYS)\n";
										break;
								}
							}
							if (sql_type.startsWith("timestamp")) {
								buf += ("\t@Column\n\t@Type(type=\"timestamp\")");
								buf += ("\n\tprivate Date " + name + " = null;");
								type = "Date";
							} else if (sql_type.startsWith("date")) {
								buf += ("\t@Column\n\t@Type(type=\"date\")");
								buf += ("\n\tprivate Date " + name + " = null;");
								type = "Date";
							} else if (sql_type.startsWith("time")) {
								buf += ("\t@Column\n\t@Type(type=\"time\")");
								buf += ("\n\tprivate Date " + name + " = null;");
								type = "Date";
							} else {
								MessageDialog.openInformation(shell, "Info", "Unknown type:\n" + sql_type);
								continue;
							}
					}
				}
				
				if (!id && columnHeadings.containsKey(name.toUpperCase())) {
					buf += "\n\t" + "/** get \"" + columnHeadings.get(name.toUpperCase()) + "\"*/";
				}
				buf += ("\n\tpublic " + type + " get" + getSetName + "() { return " + name + "; }");
				if (!id && columnHeadings.containsKey(name.toUpperCase())) {
					buf += "\n\t" + "/** set \"" + columnHeadings.get(name.toUpperCase()) + "\"*/";
				}
				buf += ("\n\tpublic void set" + getSetName + "(final " + type + " " + name + ") { this." + name + " = " + name + "; }\n");
				
				if (buf.contains("@Generated(GenerationTime.ALWAYS)") && !buf.contains("import org.hibernate.annotations.Generated")) {
					buf = buf.replaceFirst(Pattern.quote("import org.hibernate.annotations.Type;"), "import org.hibernate.annotations.Generated;\nimport org.hibernate.annotations.GenerationTime;\nimport org.hibernate.annotations.Type;");
				}
			}
		}
	}
}
