/**
 * Copyright (c) 2016-2019 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 com.zsmartsystems.zigbee.console;

import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import com.zsmartsystems.zigbee.CommandResult;
import com.zsmartsystems.zigbee.ZigBeeEndpoint;
import com.zsmartsystems.zigbee.ZigBeeNetworkManager;
import com.zsmartsystems.zigbee.zcl.ZclAttribute;
import com.zsmartsystems.zigbee.zcl.ZclCluster;
import com.zsmartsystems.zigbee.zcl.ZclStatus;
import com.zsmartsystems.zigbee.zcl.clusters.general.ReadAttributesResponse;
import com.zsmartsystems.zigbee.zcl.field.ReadAttributeStatusRecord;

/**
 *
 * @author Chris Jackson
 *
 */
public class ZigBeeConsoleAttributeReadCommand extends ZigBeeConsoleAbstractCommand {

    @Override
    public String getCommand() {
        return "read";
    }

    @Override
    public String getDescription() {
        return "Read one or more attributes.";
    }

    @Override
    public String getSyntax() {
        return "ENDPOINT CLUSTER ATTRIBUTE1 [ATTRIBUTE2 ...]";
    }

    @Override
    public String getHelp() {
        return "";
    }

    @Override
    public void process(ZigBeeNetworkManager networkManager, String[] args, PrintStream out)
            throws IllegalArgumentException, InterruptedException, ExecutionException {
        if (args.length < 4) {
            throw new IllegalArgumentException("Invalid number of arguments");
        }

        final ZigBeeEndpoint endpoint = getEndpoint(networkManager, args[1]);
        ZclCluster cluster = getCluster(endpoint, args[2]);

        final Map<Integer, String> attributes = new HashMap<>();
        for (int i = 3; i < args.length; i++) {
            Integer attributeId = parseAttribute(args[i]);
            ZclAttribute attribute = cluster.getAttribute(attributeId);
            attributes.put(attributeId,
                    attribute != null ? attribute.getName() : String.format("Attribute %d", attributeId));
        }

        out.println("Reading " + printCluster(cluster) + ", attributes " + String.join(", ", attributes.values()));

        CommandResult result = cluster.read(new ArrayList<>(attributes.keySet())).get();

        if (result.isSuccess()) {
            final ReadAttributesResponse response = result.getResponse();

            out.println(String.format("Response for cluster 0x%04x", response.getClusterId()));

            if (response.getRecords().size() == 0) {
                out.println("No records returned");
                return;
            }

            for (ReadAttributeStatusRecord statusRecord : response.getRecords()) {
                if (statusRecord.getStatus() == ZclStatus.SUCCESS) {
                    out.println("Attribute " + statusRecord.getAttributeIdentifier() + ", type "
                            + statusRecord.getAttributeDataType() + ", value: " + statusRecord.getAttributeValue());
                } else {
                    out.println("Attribute " + statusRecord.getAttributeIdentifier() + " error: "
                            + statusRecord.getStatus());
                }
            }

            return;
        } else {
            out.println("Error executing command: " + result);
            return;
        }
    }
}

@@ -1362,16 +1362,38 @@
 TE2 ...%5D
+ %5BPERIOD=x%5D %5BCYCLES=x%5D
 %22;%0A    %7D
@@ -1915,24 +1915,85 @@
  args%5B2%5D);%0A%0A
+        int repeatPeriod = 0;%0A        int repeatCycles = 10;%0A
         fina
@@ -2089,24 +2089,541 @@
 gth; i++) %7B%0A
+            String cmd%5B%5D = args%5Bi%5D.split(%22=%22);%0A            if (cmd != null && cmd.length == 2) %7B%0A                switch (cmd%5B0%5D.toLowerCase()) %7B%0A                    case %22period%22:%0A                        repeatPeriod = parseInteger(cmd%5B1%5D);%0A                        break;%0A                    case %22cycles%22:%0A                        repeatCycles = parseInteger(cmd%5B1%5D);%0A                        break;%0A                    default:%0A                        break;%0A                %7D%0A                continue;%0A            %7D%0A
             
@@ -2928,16 +2928,72 @@
 Reading 
+endpoint %22 + endpoint.getEndpointAddress() + %22, cluster 
 %22 + prin
@@ -3009,16 +3009,32 @@
 cluster)
+%0A               
  + %22, at
@@ -3084,19 +3084,561 @@
 alues())
-);%0A
+%0A                + (repeatPeriod == 0 ? %22%22 : (%22 @period = %22 + repeatPeriod + %22 sec%22)));%0A%0A        for (int cnt = 0; cnt %3C repeatCycles; cnt++) %7B%0A            if (!readAttribute(out, cluster, attributes)) %7B%0A                break;%0A            %7D%0A            if (repeatPeriod == 0) %7B%0A                break;%0A            %7D%0A            Thread.sleep(repeatPeriod * 1000L);%0A        %7D%0A    %7D%0A%0A    private boolean readAttribute(PrintStream out, ZclCluster cluster, Map%3CInteger, String%3E attributes)%0A            throws InterruptedException, ExecutionException %7B
 %0A       
@@ -4045,32 +4045,38 @@
           return
+ false
 ;%0A            %7D%0A
@@ -4665,32 +4665,37 @@
           return
+ true
 ;%0A        %7D else
@@ -4778,16 +4778,22 @@
   return
+ false
 ;%0A      

Add options for continued polling of attributes (#639)