gt:             clientSocket = new Socket(host, cliport);
context: /**
   * Copyright (c) 2010-2017 by the respective copyright holders.
   *
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   */
  package org.openhab.binding.squeezebox.handler;
  
  import static org.openhab.binding.squeezebox.SqueezeBoxBindingConstants.SQUEEZEBOXSERVER_THING_TYPE;
  
  import java.io.BufferedReader;
  import java.io.BufferedWriter;
  import java.io.IOException;
  import java.io.InputStreamReader;
  import java.io.OutputStreamWriter;
  import java.io.UnsupportedEncodingException;
  import java.net.Socket;
  import java.net.URLDecoder;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import java.util.concurrent.ScheduledFuture;
  import java.util.concurrent.TimeUnit;
  
  import org.apache.commons.lang.StringUtils;
  import org.eclipse.smarthome.core.thing.Bridge;
  import org.eclipse.smarthome.core.thing.ChannelUID;
  import org.eclipse.smarthome.core.thing.Thing;
  import org.eclipse.smarthome.core.thing.ThingStatus;
  import org.eclipse.smarthome.core.thing.ThingStatusDetail;
  import org.eclipse.smarthome.core.thing.ThingTypeUID;
  import org.eclipse.smarthome.core.thing.binding.BaseBridgeHandler;
  import org.eclipse.smarthome.core.thing.binding.ThingHandler;
  import org.eclipse.smarthome.core.types.Command;
  import org.openhab.binding.squeezebox.config.SqueezeBoxServerConfig;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  /**
   * Handles connection and event handling to a SqueezeBox Server.
   *
   * @author Markus Wolters
   * @author Ben Jones
   * @author Dan Cunningham (OH2 Port)
   * @author Daniel Walters - Fix player discovery when player name contains spaces
   * @author Mark Hilbush - Improve reconnect logic. Improve player status updates.
   * @author Mark Hilbush - Implement AudioSink and notifications
   * @author Mark Hilbush - Added duration channel
   * @author Mark Hilbush - Added login/password authentication for LMS
   */
  public class SqueezeBoxServerHandler extends BaseBridgeHandler {
      private Logger logger = LoggerFactory.getLogger(SqueezeBoxServerHandler.class);
  
      public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
              .singleton(SQUEEZEBOXSERVER_THING_TYPE);
  
      // time in seconds to try to reconnect
      private int RECONNECT_TIME = 60;
  
      // the value by which the volume is changed by each INCREASE or
      // DECREASE-Event
      private static final int VOLUME_CHANGE_SIZE = 5;
      private static final String NEW_LINE = System.getProperty("line.separator");
  
      private List<SqueezeBoxPlayerEventListener> squeezeBoxPlayerListeners = Collections
              .synchronizedList(new ArrayList<SqueezeBoxPlayerEventListener>());
      private Map<String, SqueezeBoxPlayer> players = Collections
              .synchronizedMap(new HashMap<String, SqueezeBoxPlayer>());
      // client socket and listener thread
      private Socket clientSocket;
      private SqueezeServerListener listener;
      private ScheduledFuture<?> reconnectFuture;
  
      private String host;
  
      private int cliport;
  
      private int webport;
  
      private String userId;
  
      private String password;
  
      public SqueezeBoxServerHandler(Bridge bridge) {
          super(bridge);
      }
  
      @Override
      public void initialize() {
          logger.debug("initializing server handler for thing {}", getThing());
  
          scheduler.schedule(new Runnable() {
  
              @Override
              public void run() {
                  connect();
              }
          }, 0, TimeUnit.SECONDS);
      }
  
      @Override
      public void dispose() {
          logger.debug("disposing server handler for thing {}", getThing());
          cancelReconnect();
          disconnect();
      }
  
      @Override
      public void handleCommand(ChannelUID channelUID, Command command) {
      }
  
      /**
       * Checks if we have a connection to the Server
       *
       * @return
       */
      public synchronized boolean isConnected() {
          if (clientSocket == null) {
              return false;
          }
  
          // NOTE: isConnected() returns true once a connection is made and will
          // always return true even after the socket is closed
          // http://stackoverflow.com/questions/10163358/
          return clientSocket.isConnected() && !clientSocket.isClosed();
      }
  
      public void mute(String mac) {
          setVolume(mac, 0);
      }
  
      public void unMute(String mac, int unmuteVolume) {
          setVolume(mac, unmuteVolume);
      }
  
      public void powerOn(String mac) {
          sendCommand(mac + " power 1");
      }
  
      public void powerOff(String mac) {
          sendCommand(mac + " power 0");
      }
  
      public void syncPlayer(String mac, String player2mac) {
          sendCommand(mac + " sync " + player2mac);
      }
  
      public void unSyncPlayer(String mac) {
          sendCommand(mac + " sync -");
      }
  
      public void play(String mac) {
          sendCommand(mac + " play");
      }
  
      public void playUrl(String mac, String url) {
          sendCommand(mac + " playlist play " + url);
      }
  
      public void pause(String mac) {
          sendCommand(mac + " pause 1");
      }
  
      public void unPause(String mac) {
          sendCommand(mac + " pause 0");
      }
  
      public void stop(String mac) {
          sendCommand(mac + " stop");
      }
  
      public void prev(String mac) {
          sendCommand(mac + " playlist index -1");
      }
  
      public void next(String mac) {
          sendCommand(mac + " playlist index +1");
      }
  
      public void clearPlaylist(String mac) {
          sendCommand(mac + " playlist clear");
      }
  
      public void deletePlaylistItem(String mac, int playlistIndex) {
          sendCommand(mac + " playlist delete " + playlistIndex);
      }
  
      public void playPlaylistItem(String mac, int playlistIndex) {
          sendCommand(mac + " playlist index " + playlistIndex);
      }
  
      public void addPlaylistItem(String mac, String url) {
          sendCommand(mac + " playlist add " + url);
      }
  
      public void setPlayingTime(String mac, int time) {
          sendCommand(mac + " time " + time);
      }
  
      public void setRepeatMode(String mac, int repeatMode) {
          sendCommand(mac + " playlist repeat " + repeatMode);
      }
  
      public void setShuffleMode(String mac, int shuffleMode) {
          sendCommand(mac + " playlist shuffle " + shuffleMode);
      }
  
      public void volumeUp(String mac, int currentVolume) {
          setVolume(mac, currentVolume + VOLUME_CHANGE_SIZE);
      }
  
      public void volumeDown(String mac, int currentVolume) {
          setVolume(mac, currentVolume - VOLUME_CHANGE_SIZE);
      }
  
      public void setVolume(String mac, int volume) {
          if (0 > volume) {
              volume = 0;
          } else if (volume > 100) {
              volume = 100;
          }
          sendCommand(mac + " mixer volume " + String.valueOf(volume));
      }
  
      public void showString(String mac, String line) {
          showString(mac, line, 5);
      }
  
      public void showString(String mac, String line, int duration) {
          sendCommand(mac + " show line1:" + line + " duration:" + String.valueOf(duration));
      }
  
      public void showStringHuge(String mac, String line) {
          showStringHuge(mac, line, 5);
      }
  
      public void showStringHuge(String mac, String line, int duration) {
          sendCommand(mac + " show line1:" + line + " font:huge duration:" + String.valueOf(duration));
      }
  
      public void showStrings(String mac, String line1, String line2) {
          showStrings(mac, line1, line2, 5);
      }
  
      public void showStrings(String mac, String line1, String line2, int duration) {
          sendCommand(mac + " show line1:" + line1 + " line2:" + line2 + " duration:" + String.valueOf(duration));
      }
  
      /**
       * Send a generic command to a given player
       *
       * @param playerId
       * @param command
       */
      public void playerCommand(String mac, String command) {
          sendCommand(mac + " " + command);
      }
  
      /**
       * Ask for player list
       */
      public void requestPlayers() {
          sendCommand("players 0");
      }
  
      /**
       * Login to server
       */
      public void login() {
          if (StringUtils.isEmpty(userId)) {
              return;
          }
          logger.debug("Logging into Squeeze Server using userId={}", userId);
          sendCommand("login " + userId + " " + password);
      }
  
      /**
       * Send a command to the Squeeze Server.
       */
      private synchronized void sendCommand(String command) {
  
          if (getThing().getStatus() != ThingStatus.ONLINE) {
              return;
          }
  
          if (!isConnected()) {
              logger.debug("no connection to squeeze server when trying to send command, returning...");
              return;
          }
  
          logger.debug("Sending command: {}", command);
          try {
              BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
              writer.write(command + NEW_LINE);
              writer.flush();
          } catch (IOException e) {
              logger.error("Error while sending command to Squeeze Server ({}) ", command, e);
          }
      }
  
      /**
       * Connects to a SqueezeBox Server
       */
      private void connect() {
          logger.trace("attempting to get a connection to the server");
          disconnect();
          SqueezeBoxServerConfig config = getConfigAs(SqueezeBoxServerConfig.class);
          this.host = config.ipAddress;
          this.cliport = config.cliport;
          this.webport = config.webport;
          this.userId = config.userId;
          this.password = config.password;
  
          if (StringUtils.isEmpty(this.host)) {
              updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.CONFIGURATION_ERROR, "host is not set");
              return;
          }
          try {
  