// License: GPL. See LICENSE file for details.
package org.openstreetmap.josm.gui.download;

import static org.openstreetmap.josm.tools.I18n.tr;

import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.logging.Logger;

import javax.swing.ButtonGroup;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.tools.GBC;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
 * ID Number Selector
 * 
 * Input method for the "Download from OSM" dialog box.  Given an OSM element ID number,
 * it finds the center point and loads small additional area on each side.
 * Very handy if you've found a problem element in an XML or database dump.
 * 
 * Example: enter node id 1, to see the first node ever added to OSM
 * 
 * TODO: finish support for relations / changesets
 * TODO: offer radius in meters, not degrees
 *
 * @author Bryce Nesbitt, April 2011
 *
 */
public class IdNumberSelection implements DownloadSelection {
    private static final Logger logger = Logger.getLogger(IdNumberSelection.class.getName());

    private DownloadDialog parent;
    private JTextField   osmid          = new JTextField(21);
    private JTextField   osmradius      = new JTextField(".001",6);

    private JRadioButton radioChangeset = new JRadioButton(tr("Changeset"));
    private JRadioButton radioRelation  = new JRadioButton(tr("Relation"));
    private JRadioButton radioNode      = new JRadioButton(tr("Node"));
    private JRadioButton radioWay       = new JRadioButton(tr("Way"));

    private String lasturl = "";
    private double lastradius = 0;

    public void addGui(final DownloadDialog gui) {
        BoundingBoxBuilder bboxbuilder = new BoundingBoxBuilder();
        osmid.addFocusListener (bboxbuilder);
        osmid.addActionListener(bboxbuilder);
        osmradius.addFocusListener (bboxbuilder);
        osmradius.addActionListener(bboxbuilder);
        radioRelation.addActionListener(bboxbuilder);
        radioNode.addActionListener(bboxbuilder);
        radioWay.addActionListener(bboxbuilder);
        radioRelation.setMnemonic(KeyEvent.VK_R);
        radioNode.setMnemonic(KeyEvent.VK_N);
        radioWay.setMnemonic(KeyEvent.VK_W);

        ButtonGroup radioGroup = new ButtonGroup();
        radioGroup.add(radioWay);
        radioGroup.add(radioNode);
        radioGroup.add(radioRelation);
        radioRelation.setEnabled(false);
        radioNode.setEnabled(true);
        radioWay.setEnabled(false);

        radioNode.setSelected(true);

        final JPanel dlg = new JPanel(new GridBagLayout());
        dlg.add(new JLabel(tr("Within")), GBC.std().insets(10,20,5,0));
        dlg.add(osmradius,  GBC.std().insets(0,20,0,0));
        dlg.add(new JLabel(tr("degrees of")), GBC.std().insets(10,20,5,0));
        dlg.add(radioNode,      GBC.std().insets(0,20,0,0));
        dlg.add(radioWay,       GBC.std().insets(0,20,0,0));
        dlg.add(radioRelation,  GBC.std().insets(0,20,0,0));
        dlg.add(new JLabel(tr("number")), GBC.std().insets(10,20,5,0));
        dlg.add(osmid,          GBC.std().insets(0,20,0,0));

        gui.addDownloadAreaSelector(dlg, tr("ID"));
        parent = gui;
    }

    public void setDownloadArea(Bounds area) {
    }

    class BoundingBoxBuilder extends FocusAdapter implements ActionListener {

        protected void refreshBounds() {
            double mylon=0,mylat=0,radius=0;
            String url;

            // Process text input fields
            // Extract the OSM element ID and radius to use as a center point
            // for the download.
            int id;
            try {
                id      = Integer.parseInt(osmid.getText().trim());
                radius  = Double.parseDouble(osmradius.getText().trim());
            } catch (NumberFormatException e1) {
                Bounds b = new Bounds(0,0,0,0);
                parent.boundingBoxChanged(b, IdNumberSelection.this);
                return;
            }

            // Build URL based on object type to look up.
            if (radioRelation.isSelected()) {
                url = "http://api.openstreetmap.org/api/0.6/relation/"+id;
            } else if(radioNode.isSelected()) {
                url = "http://api.openstreetmap.org/api/0.6/node/"+id;
            } else {
                url = "http://api.openstreetmap.org/api/0.6/way/"+id;
            }

            // Don't requery the API each time a tab is clicked
            if( url == lasturl && lastradius == radius )
                return;
            lasturl    = url;
            lastradius = radius;

            // Use the DOM to load an element from the API, and parse out the lat/lon.
            try {
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                DocumentBuilder db = dbf.newDocumentBuilder();
                logger.info(url);
                Document doc = db.parse(url);
                Node         node = doc.getElementsByTagName("node").item(0);
                NamedNodeMap nmap = node.getAttributes();
                mylat = Double.parseDouble(nmap.getNamedItem("lat").getNodeValue());
                mylon = Double.parseDouble(nmap.getNamedItem("lon").getNodeValue());
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                mylat = mylon = 0;
            }

            Bounds b = new Bounds(mylat-radius,mylon-radius,mylat+radius,mylon+radius);
            parent.boundingBoxChanged(b, IdNumberSelection.this);
        }
        @Override
        public void focusLost(FocusEvent e) {
            refreshBounds();
        }
        public void actionPerformed(ActionEvent e) {
            refreshBounds();
        }
    }
}

