public void drawPopup(RowData r, Graphics g, int width, int height) {
		int useWidth = width - 100;
		int halfWidth = useWidth / 2;
		int useHeight = height - 100;
		int useNRows = (config.getNRows() * 3) / 2;
		int curRowHeight = useHeight / useNRows;
		String font = config.getFontName();

		try {
			int rowOffset = 0;

			initPopup(g, useWidth, useHeight);

			if (r.getType() == DataType.TEXT) {

				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, (String)r.getObject1());

				JavNag javNag = new JavNag();
				javNag.setUserAgent(CoffeeSaint.version);
				javNag.setSocketTimeout(config.getSleepTime() * 1000);
				int prevNHosts = 0, prevNServices = 0;;
				for(NagiosDataSource dataSource : config.getNagiosDataSources())
				{
					String source = "???", stats;

					long startLoadTs = System.currentTimeMillis();

					if (dataSource.getType() == NagiosDataSourceType.TCP) {
						source = dataSource.getHost() + " " + dataSource.getPort();
						javNag.loadNagiosData(dataSource.getHost(), dataSource.getPort(), dataSource.getVersion(), false, dataSource.getPrettyName());
					}
					else if (dataSource.getType() == NagiosDataSourceType.ZTCP) {
						source = dataSource.getHost() + " " + dataSource.getPort();
						javNag.loadNagiosData(dataSource.getHost(), dataSource.getPort(), dataSource.getVersion(), true, dataSource.getPrettyName());
					}
					else if (dataSource.getType() == NagiosDataSourceType.HTTP) {
						source = "" + dataSource.getURL();
						javNag.loadNagiosData(dataSource.getURL(), dataSource.getVersion(), dataSource.getUsername(), dataSource.getPassword(), config.getAllowHTTPCompression(), dataSource.getPrettyName());
					}
					else if (dataSource.getType() == NagiosDataSourceType.FILE) {
						source = dataSource.getFile();
						javNag.loadNagiosData(dataSource.getFile(), dataSource.getVersion(), dataSource.getPrettyName());
					}
					else if (dataSource.getType() == NagiosDataSourceType.LS) {
						source = dataSource.getHost() + " " + dataSource.getPort();
						javNag.loadNagiosDataLiveStatus(dataSource.getHost(), dataSource.getPort(), dataSource.getPrettyName());
					}

					Totals totals = javNag.calculateStatistics();
					stats = "Load time: " + (System.currentTimeMillis() - startLoadTs) / 1000.0 + "s, hosts: " + (totals.getNHosts() - prevNHosts) + ", services: " + (totals.getNServices() - prevNServices);
					prevNHosts = totals.getNHosts();
					prevNServices = totals.getNServices();

					putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "Nagios source: " + source);
					putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "  " + stats);
				}
				Totals totals = javNag.calculateStatistics();

				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "Total hosts: " + totals.getNHosts() + ", services: " + totals.getNServices());
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "OK: " + totals.getNOk() + ", warning: " + totals.getNWarning() + ", critical: " + totals.getNCritical());
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "UP: " + totals.getNUp() + ", down: " + totals.getNDown() + ", unr.: " + totals.getNUnreachable() + ", pending: " + totals.getNPending());
				String latency = "" + javNag.getAvgCheckLatency();
				if (latency.length() > 5)
					latency = latency.substring(0, 5);
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "Average check latency: " + latency + ", last check age: " + javNag.findMostRecentCheckAge() + "s");
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "Problems acked: " + totals.getNAcked() + ", flapping: " + totals.getNFlapping());
			}
			else
			{
				g.setColor(Color.BLACK);

				String which = getEitherParameter(r, "host_name");
				if (r.getType() == DataType.SERVICE)
					which += " / " + ((Service)r.getObject2()).getServiceName();
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, which);

				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, getEitherParameter(r, "plugin_output"));
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "exec time: " + getEitherParameter(r, "check_execution_time") + ", latency: " + getEitherParameter(r, "check_latency") + ", " + getEitherParameter(r, "performance_data"));

				putLine(g, font, 51, 51 + curRowHeight * rowOffset, halfWidth, curRowHeight, "last check: " + cnvSec(getEitherParameter(r, "last_check")));
				putLine(g, font, 51 + halfWidth, 51 + curRowHeight * (rowOffset++), halfWidth, curRowHeight, "next: " + cnvSec(getEitherParameter(r, "next_check")));

				putLine(g, font, 51, 51 + curRowHeight * rowOffset, halfWidth, curRowHeight, "last state change: " + cnvSec(getEitherParameter(r, "last_state_change")));
				putLine(g, font, 51 + halfWidth, 51 + curRowHeight * (rowOffset++), halfWidth, curRowHeight, "last hard change: " + cnvSec(getEitherParameter(r, "last_hard_state_change")));

				if (r.getType() == DataType.HOST) {
					putLine(g, font, 51, 51 + curRowHeight * rowOffset, halfWidth, curRowHeight, "last up: " + cnvSec(getEitherParameter(r, "last_time_up")));
					putLine(g, font, 51 + halfWidth, 51 + curRowHeight * (rowOffset++), halfWidth, curRowHeight, "last down: " + cnvSec(getEitherParameter(r, "last_time_down")));
					putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "last time unreachable: " + cnvSec(getEitherParameter(r, "last_time_unreachable")));
				}
				else {
					putLine(g, font, 51, 51 + curRowHeight * rowOffset, halfWidth, curRowHeight, "last ok: " + cnvSec(getEitherParameter(r, "last_time_ok")));
					putLine(g, font, 51 + halfWidth, 51 + curRowHeight * (rowOffset++), halfWidth, curRowHeight, "warning: " + cnvSec(getEitherParameter(r, "last_time_warning")));
					putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "last critical: " + cnvSec(getEitherParameter(r, "last_time_critical")));
				}
				putLine(g, font, 51, 51 + curRowHeight * rowOffset, halfWidth, curRowHeight, "last notification: " + cnvSec(getEitherParameter(r, "last_notification")));
				putLine(g, font, 51 + halfWidth, 51 + curRowHeight * (rowOffset++), halfWidth, curRowHeight, "next: " + cnvSec(getEitherParameter(r, "next_notification")));
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "last update: " + cnvSec(getEitherParameter(r, "last_update")));
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "is flapping: " + getEitherParameter(r, "is_flapping") + ", state change: " + getEitherParameter(r, "percent_state_change") + "%");
				putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "acked: " + getEitherParameter(r, "problem_has_been_acknowledged") + ", active checks: " + getEitherParameter(r, "active_checks_enabled") + ", passive checks: " + getEitherParameter(r, "passive_checks_enabled"));
				String entry_time = getEitherParameter(r, "entry_time");
				if (entry_time.equals("?") == false) {
					putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "Comment entry time: " + cnvSec(entry_time) + ":");
					putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, "comment: " + getEitherParameter(r, "comment_data"));
				}

				String longPluginOutput = getEitherParameter(r, "long_plugin_output");
				while(rowOffset < useNRows && longPluginOutput != null) {
					int lf = longPluginOutput.indexOf("\n");
					String emit = "";
					if (lf == -1) {
						emit = longPluginOutput.trim();
						longPluginOutput = null;
					}
					else {
						if (lf > 0)
							emit = longPluginOutput.substring(0, lf - 1).trim();
						if ((lf + 1) < longPluginOutput.length())
							longPluginOutput = longPluginOutput.substring(lf + 1);
						else
							longPluginOutput = null;
					}
					if (emit.length() > 0)
						putLine(g, font, 51, 51 + curRowHeight * (rowOffset++), useWidth, curRowHeight, emit);
				}

				if (rowOffset < useNRows && config.getSparkLineWidth() > 0) {
					BufferedImage sparkLine = coffeeSaint.getSparkLine((Host)r.getObject1(), (Service)r.getObject2(), useWidth - 2, curRowHeight, false);
					g.drawImage(sparkLine, 51, 51 + rowOffset * curRowHeight, null);
				}
			}
		}
		catch(Exception e) {
			statistics.incExceptions();

			CoffeeSaint.showException(e);

			if (g != null)
				showCoffeeSaintProblem(e, g, width, curRowHeight);
		}
	}