package com.googlecode.jmxtrans.model.output;

import java.io.PrintWriter;
import java.io.Writer;
import java.net.Socket;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.jmxtrans.model.Query;
import com.googlecode.jmxtrans.model.Result;
import com.googlecode.jmxtrans.util.BaseOutputWriter;
import com.googlecode.jmxtrans.util.JmxUtils;

/**
 * This output writer sends data to a host/port combination
 * in the Graphite format.
 *
 * @see <a href="http://graphite.wikidot.com/getting-your-data-into-graphite">http://graphite.wikidot.com/getting-your-data-into-graphite</a>
 * @author jon
 */
public class GraphiteWriter extends BaseOutputWriter {

    private static final Logger log = LoggerFactory.getLogger(GraphiteWriter.class);
    public static final String ROOT_PREFIX = "rootPrefix";

    private String host = null;
    private Integer port = null;
    private String rootPrefix = "servers";

    /** */
    public GraphiteWriter() {
    }

    /** */
    public void validateSetup() throws Exception {
        host = (String) this.getSettings().get(HOST);
        port = (Integer) this.getSettings().get(PORT);

        if (host == null || port == null) {
            throw new RuntimeException("Host and port can't be null");
        }

        String rootPrefixTmp = (String) this.getSettings().get(ROOT_PREFIX);
        if (rootPrefixTmp != null) {
        	rootPrefix = rootPrefixTmp;
        }
    }

    /** */
    public void doWrite(Query query) throws Exception {
        Writer writer = connect();
        try {
            for (Result r : query.getResults()) {
                if (isDebugEnabled()) {
                    log.debug(r.toString());
                }
                Map<String, Object> resultValues = r.getValues();
                if (resultValues != null) {
                    for (Entry<String, Object> values : resultValues.entrySet()) {
                        if (JmxUtils.isNumeric(values.getValue())) {
                            String keyStr = null;
                            if (values.getKey().startsWith(r.getAttributeName())) {
                                keyStr = values.getKey();
                            } else {
                                keyStr = r.getAttributeName() + "." + values.getKey();
                            }

                            String alias = null;
                            if (query.getServer().getAlias() != null) {
                                alias = query.getServer().getAlias();
                            } else {
                                alias = query.getServer().getHost() + "_" + query.getServer().getPort();
                                alias = cleanupStr(alias);
                            }

                            StringBuilder sb = new StringBuilder();
                            sb.append(rootPrefix);
                            sb.append(".");
                            sb.append(alias);
                            sb.append(".");

                            // Allow people to use something other than the classname as the output.
                            if (r.getClassNameAlias() != null) {
                                sb.append(r.getClassNameAlias());
                            } else {
                                sb.append(cleanupStr(r.getClassName()));
                            }

                            sb.append(".");

                            String typeName = cleanupStr(getConcatedTypeNameValues(r.getTypeName()));
                            if (typeName != null) {
                                sb.append(typeName);
                                sb.append(".");
                            }
                            sb.append(cleanupStr(keyStr));

                            sb.append(" ");
                            sb.append(values.getValue());
                            sb.append(" ");
                            sb.append(r.getEpoch() / 1000);
                            sb.append("\n");

                            String line = sb.toString();
                            if (isDebugEnabled()) {
                                log.debug("Graphite Message: " + line.trim());
                            }
                            writer.write(line);
                        }
                    }
                }
            }
            writer.flush();
        } finally {
            IOUtils.closeQuietly(writer);
        }
    }

    /** */
    private Writer connect() throws Exception {
        Socket socket = new Socket(host, port);
        return new PrintWriter(socket.getOutputStream(), true);
    }

}

@@ -1016,16 +1016,20 @@
 rvers%22;%0A
+    
 %0A    /**
@@ -1603,23 +1603,68 @@
 tion %7B%0A 
+   %09Socket socket = new Socket(host, port);%0A
        
+ 
 Writer w
@@ -1671,24 +1671,62 @@
 riter = 
-connect(
+new PrintWriter(socket.getOutputStream(), true
 );%0A     
@@ -4636,193 +4636,42 @@
     
-%7D%0A
     
-%7D%0A%0A    /** */%0A    private Writer connect() throws Exception %7B%0A        Socket socket = new Socket(host, port);%0A        return new PrintWriter(socket.getOutputStream(), true);
+socket.close();%0A        %7D
 %0A    %7D%0A
-%0A
 %7D%0A

create a new connection every time we write to graphite. not sure this is the right way to do things as it seems very expensive. but effectively this is what we were doing before except that i wasn't doing a close() on the socket at the end and i think this was leaving connections dangling.