/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package de.nplusc.izc.InstallPak;

import com.sun.jna.platform.unix.X11;
import de.nplusc.izc.tools.IOtools.FileTK;
import de.nplusc.izc.tools.IOtools.registryReader;
import de.nplusc.izc.tools.baseTools.Detectors;
import de.nplusc.izc.tools.baseTools.Messagers;
import de.nplusc.izc.tools.baseTools.Tools;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.yaml.snakeyaml.Yaml;

/**
 *
 * @author LH
 */
public class YamlInstallFiles implements InstallFilesManagerAPI
{

    private String packagesDeclaration;
    private boolean multidisk;
    private Map<String, Object> packRaw;
    private List<Map<String, String>> packagesParsed;
    private List<String> packNames;//lookup list to avoid map usage for getPacksInPackage:
    private List<String> packIDs;//internal mapping from stringname to numeric ID
    private boolean[] packsInstalled;
    private boolean[] packsScheduled;
    private boolean[] packsInstallable;
    private int[] packsParent;

    public YamlInstallFiles(String filepath)
    {
        try
        {
            packagesDeclaration = filepath;
            Yaml y = new Yaml();
            packRaw = (Map<String, Object>) y.load(new FileInputStream(filepath));
            List<String> Flags = (List<String>) packRaw.get("flags");
            if (Flags.contains("multidisk"))
            {
                multidisk = true;
            }
            List<String> startingPoints = (List<String>) packRaw.get("packagebases");
            packagesParsed = new ArrayList<>();
            packNames = new ArrayList<>();
            packIDs = new ArrayList<>();
            for (String pid : startingPoints)
            {
                Map<String, String> pret = getPackEntry(pid);
                if (!pret.isEmpty())
                {
                    packIDs.add(pid);
                    packNames.add(pret.get("Name"));
                    packagesParsed.add(pret);
                }
            }
            int packsCount = packIDs.size();
            packsInstalled = new boolean[packsCount];
            packsInstallable = new boolean[packsCount];
            packsScheduled = new boolean[packsCount];
            packsParent = new int[packsCount];
            
            for (int i = 0; i < packsCount; i++)
            {
                packsInstallable[i]=true;
                Map<String,String> pdata = packagesParsed.get(i);
                if(pdata.containsKey("detectInstall"))
                {
                    packsInstalled[i] = SharedUtils.detectInstall(pdata.get("detectInstall"));
                }
                else
                {
                    packsInstalled[i]=false;
                }
                if(pdata.containsKey("defaultEnabled"))
                {
                    packsScheduled[i] = Boolean.valueOf((pdata.get("defaultEnabled")));
                }
                else
                {
                    packsScheduled[i]=false;
                }
                if(pdata.containsKey("dependsOn"))
                {
                    packsParent[i] = packIDs.indexOf(pdata.get("dependsOn"));
                    if(packsInstallable[packsParent[i]]==false||packsScheduled[packsParent[i]])
                    {
                        packsInstallable[i]=false;
                    }
                }
                else
                {
                    packsParent[i]=-1;
                }
            }
        }
        catch (IOException ex)
        {
            ex.printStackTrace();
        }
    }

    private Map<String, String> getPackEntry(String packID)
    {
        Map<String, String> rawData = (Map<String, String>) packRaw.get(packID);
        if (rawData == null)
        {
            Messagers.SingleLineMsg("Package " + packID + " nicht deklariert! Error 0x0416414D", "Okay");
            System.exit(0x0416414D);
        }
        if (rawData.containsKey("Condition"))
        {
            boolean conditionResult = SharedUtils.checkCondition(rawData.get("Condition"));
            if (conditionResult)
            {
                if (rawData.containsKey("ifnode"))
                {
                    String fid = rawData.get("ifnode");
                    return getPackEntry(fid);
                }
                else
                {
                    return new HashMap<>();//leere map um NPX zu vermeiden da packs nicht immer vorhanden sein müssen
                }
            }
            else
            {
                if (rawData.containsKey("elsenode"))
                {
                    String fid = rawData.get("elsenode");
                    return getPackEntry(fid);
                }
                else
                {
                    return new HashMap<>();
                }

            }
        }
        return rawData;
    }



    @Override
    public String[] getPacksInPackage()
    {
        return packNames.toArray(new String[]{});
    }

    @Override
    public boolean getPackInstalled(int packnr)
    {
       return packsInstalled[packnr];
    }

    @Override
    public boolean getPackInstallable(int packid)
    {
        return  packsInstallable[packid];
    }

    @Override
    public int getDependencyParent(int packid)
    {
       return packsParent[packid];
    }

    @Override
    public int[] getChildPacks(int packID)
    {
        ArrayList<Integer> tmp = new ArrayList<>();
        for (int i = 0; i < packsParent.length; i++)
        {
            int b = packsParent[i];
            if(b==packID)
            {
                tmp.add(i);
            }
        }
        int[] r = new int[tmp.size()];
        for (int i = 0; i < tmp.size(); i++)
        {
            r[i]=tmp.get(i);
            
        }
        return r;
    }

    @Override
    public void setPackageState(int packageID, boolean state)
    {
        packsScheduled[packageID]=state;
        revalidate(packageID);
    }

    private void revalidate(int packID)
    {
        int[] c = getChildPacks(packID);
        for (int i : c)
        {
            if(packsScheduled[packID]==false||packsInstallable[packID]==false)
            {
                packsInstallable[i]=false;
            }
            if(packsScheduled[packID]&&packsInstallable[packID])
            {
                packsInstallable[i]=true;
            }
            revalidate(i);
        }
        
    }
    @Override
    public boolean getIsScheduled(int packageID)
    {
        System.out.println("checking "+packageID+"|parent="+packsParent[packageID]);
        return packsScheduled[packageID]&&packsInstallable[packageID];
    }

    @Override
    public String getPackageDescription(int packID)
    {
        Map<String,String> pd = packagesParsed.get(packID);
        return pd.containsKey("desc")?pd.get("desc"):"no description";
    }

    @Override
    public String[][] packagesQueue()
    {
        List<String[]> transferData = new ArrayList<>();
        for (int i=0;i<packagesParsed.size();i++)
        {
            Map<String, String> map =packagesParsed.get(i);
            if(!getIsScheduled(i)) continue;
            if(multidisk&&map.containsKey("waitdisk"))
            {
                String[] waitDisk = new String[]{"waitDisk",map.get("waitdisk"),"Bitte nächste DVD einlegen"};
                if(map.containsKey("waitMessage"))
                {
                    waitDisk[2]=map.get("waitMessage");
                }
                transferData.add(waitDisk);
            }
            
            String baseDir = FileTK.getFilePath(packagesDeclaration);
            if(ModeSel.diskMode)
            {
                baseDir=ModeSel.baseDir;
            }
            String[] packageItem = new String[]{"file",Tools.replaceHashmarkedVars(packagesParsed.get(i).get("script"), "basedir", baseDir)};
            transferData.add(packageItem);
        }
        return transferData.toArray(new String[][]{{}});
    }

}
