package com.android.commands.monkey.ape.jev;

import java.util.*;
import org.json.*;

/** P1 projection of an already-ranked, immutable legacy plan. Never selects history. */
final class JevPairwiseEvidenceView {
    static final class Plan {
        final JSONObject original,state,compact;
        Plan(JSONObject original)throws JSONException {
            this.original=original;state=original.getJSONObject("state");compact=new JSONObject();
            JSONObject candidates=state.getJSONObject("candidates");
            for(Iterator<?> it=candidates.keys();it.hasNext();) {
                JevDeadline.check();String id=(String)it.next();compact.put(id,compactAction(candidates.getJSONObject(id)));
            }
        }
        JSONObject project(Collection<String> candidateIds)throws JSONException {
            Set<String> selected=new LinkedHashSet<String>(candidateIds);
            if(selected.isEmpty() || selected.size()!=candidateIds.size())throw new JSONException("invalid projected candidates");
            JSONObject full=state.getJSONObject("candidates"),current=new JSONObject(),context=new JSONObject();
            for(Iterator<?> it=full.keys();it.hasNext();) {
                String id=(String)it.next();
                if(selected.contains(id))current.put(id,full.get(id));else context.put(id,compact.get(id));
            }
            if(current.length()!=selected.size())throw new JSONException("missing projected candidate evidence");
            JSONArray pairs=new JSONArray(),ids=new JSONArray(),originalPairs=original.getJSONArray("pairs");
            Set<String> histories=new HashSet<String>();Map<String,Integer> comparisons=new HashMap<String,Integer>();
            for(String id:candidateIds)ids.put(id);
            for(int i=0;i<originalPairs.length();i++) {
                JevDeadline.check();JSONObject pair=originalPairs.getJSONObject(i);String id=pair.getString("candidate");
                if(!selected.contains(id))continue;
                pairs.put(pair);histories.add(pair.getString("history"));
                comparisons.put(id,comparisons.containsKey(id)?comparisons.get(id)+1:1);
            }
            for(String id:candidateIds) {
                int expected=original.getJSONObject("coverage").getJSONObject(id).getInt("selected_history");
                if(expected<1 || expected>JevHistoryPairwiseProtocol.MAX_HISTORY || !comparisons.containsKey(id) || comparisons.get(id)!=expected)
                    throw new JSONException("incomplete projected candidate closure");
            }
            JSONObject executed=new JSONObject(),all=state.getJSONObject("executed_actions");
            for(Iterator<?> it=all.keys();it.hasNext();) {
                String id=(String)it.next();if(histories.contains(id))executed.put(id,all.get(id));
            }
            if(executed.length()!=histories.size())throw new JSONException("missing projected history evidence");
            Set<String> pageIds=new HashSet<String>();
            for(JSONObject actions:Arrays.asList(full,executed))for(Iterator<?> it=actions.keys();it.hasNext();)
                pageIds.add(actions.getJSONObject((String)it.next()).getString("source_page_id"));
            JSONObject pages=new JSONObject(),allPages=state.getJSONObject("pages");
            for(Iterator<?> it=allPages.keys();it.hasNext();) {
                String id=(String)it.next();if(pageIds.contains(id))pages.put(id,allPages.get(id));
            }
            if(pages.length()!=pageIds.size())throw new JSONException("missing projected source page");
            JSONObject view=new JSONObject().put("evidence_schema",JevHistoryPairwiseProtocol.PROJECTED_SCHEMA)
                .put("pages",pages).put("candidates",current).put("executed_actions",executed)
                .put("page_operation_context",new JSONObject().put("columns",contextColumns()).put("actions",context));
            JSONObject payload=shallowCopy(original);
            payload.put("state",view).put("pairs",pairs).put("candidate_ids",ids);
            payload.remove("input_signature");
            payload.put("evidence_view_version",JevHistoryPairwiseProtocol.EVIDENCE_VIEW_VERSION)
                .put("source_input_signature",original.getString("input_signature"));
            payload.put("input_signature",JevEvidence.digest(payload.toString()));
            return payload;
        }
    }
    static JSONObject shallowCopy(JSONObject original)throws JSONException {
        JSONObject copy=new JSONObject();
        for(Iterator<?> it=original.keys();it.hasNext();){String key=(String)it.next();copy.put(key,original.get(key));}
        return copy;
    }
    private static JSONArray contextColumns() {
        JSONArray out=new JSONArray();
        for(String key:new String[]{"source_page_id","action_type","index","class","resource_id","text","content_desc",
                "bounds","enabled","clickable","long_clickable","scrollable","checked","selected","subtree_truncated",
                "descendant_labels_path_class_resource_text_content_desc","parent_class_resource_text_content_desc",
                "local_context"})out.put(key);
        return out;
    }
    private static JSONArray compactAction(JSONObject full)throws JSONException {
        JSONArray row=new JSONArray();
        for(String key:new String[]{"source_page_id","action_type","index","class","resource_id","text","content_desc",
                "bounds","enabled","clickable","long_clickable","scrollable","checked","selected","subtree_truncated"})
            row.put(full.has(key)?full.get(key):JSONObject.NULL);
        JSONArray subtree=full.optJSONArray("target_subtree"),descendants=new JSONArray();
        if(subtree!=null)for(int i=0;i<subtree.length();i++) {
            JSONObject node=subtree.getJSONObject(i);JSONArray path=node.optJSONArray("path");
            if(i==0 && path!=null && path.length()==0)continue; // root labels are already in this context row
            JSONArray labels=new JSONArray();
            for(String key:new String[]{"path","class","resource_id","text","content_desc"})labels.put(node.has(key)?node.get(key):JSONObject.NULL);
            descendants.put(labels);
        }
        row.put(subtree==null?JSONObject.NULL:descendants);
        JSONObject parent=full.optJSONObject("parent");
        if(parent==null)row.put(JSONObject.NULL);else {
            JSONArray role=new JSONArray();
            for(String key:new String[]{"class","resource_id","text","content_desc"})role.put(parent.has(key)?parent.get(key):JSONObject.NULL);
            row.put(role);
        }
        row.put(full.has("local_context")?full.get("local_context"):JSONObject.NULL);
        return row;
    }
    private JevPairwiseEvidenceView(){}
}
