/*******************************************************************************
 * Copyright (c) 2012 Oak Ridge National Laboratory.
 * 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.csstudio.scan.ui.scandata;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.csstudio.scan.client.ScanClient;
import org.csstudio.scan.client.ScanInfoModel;
import org.csstudio.scan.client.ScanInfoModelListener;
import org.csstudio.scan.data.ScanData;
import org.csstudio.scan.data.ScanSample;
import org.csstudio.scan.server.ScanInfo;
import org.csstudio.scan.server.ScanServerInfo;

/** Model that monitors the data of a scan
 *
 *  <p>Implementation note:
 *  Fetching the whole data for every scan update
 *  plus then converting that to a "spreadsheet"
 *  in the {@link ScanDataEditor}'s {@link ScanDataModelListener}
 *  seems expensive, but causes neglegible CPU load for
 *  scans with a few thousand rows of data and a handful
 *  of devices, so "good enough" for now.
 *
 *  @author Kay Kasemir
 */
@SuppressWarnings("nls")
public class ScanDataModel implements ScanInfoModelListener
{
    /** ID of scan that we monitor */
    final private long scan_id;

    /** Scan client */
    final private ScanInfoModel scan_info_model;

    /** Most recent scan data */
    private ScanData scan_data = null;

    /** Last sample serial of scan data */
    private long last_scan_data_serial = -1;

    /** Listener to notify about updates in the scan's data */
    final private ScanDataModelListener listener;

    /** Initialize
     *  @param scan_id ID of scan to monitor
     *  @param listener {@link ScanDataModelListener}
     *  @throws Exception on error
     */
    public ScanDataModel(final long scan_id, final ScanDataModelListener listener) throws Exception
    {
        this.scan_id = scan_id;
        scan_info_model = ScanInfoModel.getInstance();
        this.listener = listener;
        scan_info_model.addListener(this);
    }

    /** Must be called to release sources when done */
    public void release()
    {
        scan_info_model.removeListener(this);
        scan_info_model.release();
    }

    /** {@inheritDoc} */
    @Override
    public void scanServerUpdate(final ScanServerInfo server_info)
    {
        // Ignored
    }

    /** @return most recent scan data. May be <code>null</code> */
    public synchronized ScanData getScanData()
    {
        return scan_data;
    }

    /** {@inheritDoc} */
    @Override
    public void scanUpdate(final List<ScanInfo> infos)
    {
        // Skip querying a scan once server indicated that it's unknown
        if (last_scan_data_serial == ScanClient.UNKNOWN_SCAN_SERIAL)
            return;

        try
        {
            // Any change in the data?
            final ScanClient client = scan_info_model.getScanClient();
            final long serial = client.getLastScanDataSerial(scan_id);
            if (serial == last_scan_data_serial)
                return;

            // Get data
            final ScanData data;
            if (serial == ScanClient.UNKNOWN_SCAN_SERIAL)
            {
                Map<String, List<ScanSample>> unknown = new HashMap<>();
                unknown.put("Unknown Scan", Collections.emptyList());
                data = new ScanData(unknown);
            }
            else
                data = client.getScanData(scan_id);
            synchronized (this)
            {
                scan_data = data;
            }
            last_scan_data_serial = serial;
            // Update listener
            listener.updateScanData(data);
        }
        catch (Exception ex)
        {
            Logger.getLogger(getClass().getName()).log(Level.WARNING, "Cannot get scan data", ex);
        }
    }

    /** {@inheritDoc} */
    @Override
    public void connectionError()
    {
        // Ignored
    }
}

@@ -1492,16 +1492,268 @@
 tener%0A%7B%0A
+    private static final ScanData UNKNOWN_SCAN;%0A%0A    static%0A    %7B%0A        final Map%3CString, List%3CScanSample%3E%3E unknown = new HashMap%3C%3E();%0A        unknown.put(%22Unknown Scan%22, Collections.emptyList());%0A        UNKNOWN_SCAN = new ScanData(unknown);%0A    %7D%0A%0A
     /** 
@@ -1778,24 +1778,24 @@
  monitor */%0A
-
     final pr
@@ -1925,32 +1925,41 @@
  */%0A    private 
+volatile 
 ScanData scan_da
@@ -3002,29 +3002,16 @@
  public 
-synchronized 
 ScanData
@@ -3658,34 +3658,19 @@
 ata data
-;%0A            if (
+ = 
 serial =
@@ -3693,33 +3693,32 @@
 NOWN_SCAN_SERIAL
-)
 %0A            %7B%0A 
@@ -3706,34 +3706,32 @@
 IAL%0A            
-%7B%0A
                 
@@ -3734,180 +3734,26 @@
     
-Map%3CString, List%3CScanSample%3E%3E unknown = new HashMap%3C%3E();%0A                unknown.put(%22Unknown Scan%22, Collections.emptyList());%0A                data = new ScanData(unknown);
+    ? UNKNOWN_SCAN
 %0A   
@@ -3753,34 +3753,32 @@
 CAN%0A            
-%7D%0A
             else
@@ -3776,14 +3776,8 @@
     
- else%0A
     
@@ -3785,21 +3785,9 @@
     
-       data =
+:
  cli
@@ -3816,58 +3816,8 @@
 d);%0A
-            synchronized (this)%0A            %7B%0A    
     
@@ -3846,22 +3846,8 @@
 ta;%0A
-            %7D%0A
     

Remove sync. from scan data model