import os, twccommon.Log, string, glob, twc, twc.dsmarshal, sys
dsm = twc.dsmarshal

class ConfigObject:
    def __init__(self, config_dict):
        for key in config_dict:
            setattr(self, key, config_dict[key])

_config = ConfigObject({
    'appName': 'execd',
    'channel': 'SystemEventChannel',
    'pluginRoot': '/media/usr/twc/domestic/plugin',
    'imageCutTool': '/media/usr/twc/digi/util/imagecut',
    'vectorCutTool': '/media/usr/twc/digi/util/vectorcut',
    'mapRoot': '/media/usr/twc/domestic/data/map.cuts',
    'imageRoot': '/media/usr/twc/domestic/data/volatile/images',
    'resourceRoot': '/rsrc',
    'pidFileName': '/media/usr/twc/domestic/data/pid',
    'radarImageScalingMethod': 'fixedPalette',
    'enableSmoothing': 1
})


class DSMarshalStruct:
    def __init__(self):
        pass

    def __repr__(self):
        return str(self.__dict__)

def dsmarshal_get(basekey):
    path = "/twc/data/datastore/ds.dat"
    try:
        f = open(path, "r")
    except IOError:
        return None

    lines = []
    while 1:
        line = f.readline()
        if not line:
            break
        parts = line.strip().split("\x1c")
        if len(parts) >= 2:
            lines.append((parts[0], parts[1]))

    f.close()

    # Check if basekey itself has a _dsmarshal marker
    has_dsmarshal = 0
    for k, v in lines:
        if k == basekey + "._dsmarshal":
            has_dsmarshal = 1
            break

    if not has_dsmarshal:
        # No _dsmarshal marker, check for simple key
        for k, v in lines:
            if k == basekey:
                return v
        return None

    # Build the structure from all matching keys
    # We need to determine if the root should be a list or dict
    is_root_list = 0
    for k, v in lines:
        if not k.startswith(basekey + "."):
            continue
        if k == basekey + "._dsmarshal":
            continue
        
        suffix = k[len(basekey) + 1:]
        first_part = suffix.split(".")[0]
        try:
            int(first_part)
            is_root_list = 1
        except:
            is_root_list = 0
        break
    
    if is_root_list:
        struct = []
    else:
        struct = {}
    
    for k, v in lines:
        if not k.startswith(basekey + "."):
            continue
        
        # Skip the _dsmarshal marker itself
        if k == basekey + "._dsmarshal":
            continue

        suffix = k[len(basekey) + 1:]
        parts = suffix.split(".")

        current = struct
        for i in range(len(parts)):
            p = parts[i]
            try:
                p_int = int(p)
                is_index = 1
            except:
                is_index = 0

            is_last = (i == len(parts) - 1)

            if is_last:
                if is_index:
                    # Extend list if needed
                    while len(current) <= p_int:
                        current.append(None)
                    current[p_int] = v
                else:
                    current[p] = v
            else:
                try:
                    int(parts[i + 1])
                    next_is_index = 1
                except:
                    next_is_index = 0

                if is_index:
                    p_int = int(p)
                    # Extend list if needed
                    while len(current) <= p_int:
                        current.append(None)

                    if current[p_int] is None:
                        if next_is_index:
                            current[p_int] = []
                        else:
                            current[p_int] = {}
                    current = current[p_int]
                else:
                    if not current.has_key(p):
                        if next_is_index:
                            current[p] = []
                        else:
                            current[p] = {}
                    current = current[p]

    # Return the structure
    if type(struct) == list:
        return struct
    
    # If it's a dict with only numeric keys, convert to list
    if type(struct) == dict and len(struct) > 0:
        all_numeric = 1
        for k in struct.keys():
            try:
                int(k)
            except:
                all_numeric = 0
                break
        
        if all_numeric:
            # Convert dict to list
            max_idx = max([int(k) for k in struct.keys()])
            result = []
            for i in range(max_idx + 1):
                if struct.has_key(str(i)):
                    result.append(struct[str(i)])
                else:
                    result.append(None)
            return result

    # Otherwise return as struct
    obj = DSMarshalStruct()
    for k2 in struct:
        setattr(obj, k2, struct[k2])
    return obj

def uninit():
    pass


def genSmoothingCommandLine(inputFile, outputFile, miles):
    cmdString = ''
    if miles <= 120:
        radius = 12
        scale = 8
        round = 0.5
        dropShadow = 4
        gaussian = 1
    elif miles >= 121 and miles <= 180:
        radius = 8
        scale = 8
        round = 0.5
        dropShadow = 4
        gaussian = 0
    elif miles >= 181 and miles <= 250:
        radius = 4
        scale = 8
        round = 0.5
        dropShadow = 4
        gaussian = 0
    elif miles >= 251 and miles <= 370:
        radius = 2
        scale = 8
        round = 0.5
        dropShadow = 4
        gaussian = 0
    elif miles > 370:
        radius = 0
        scale = 14
        round = 0.5
        dropShadow = 2
        gaussian = 0
    else:
        radius = 0
        scale = 8
        round = 0.5
        dropShadow = 2
        gaussian = 0
    cmdString += ' -i %s -o %s -r %d -s %d -R %f -d %d -g %d' % (inputFile, outputFile, radius, scale, round, dropShadow, gaussian)
    return cmdString


def buildIndexFile(rootName, validTimeString):
    """Builds an index file that contains an AVERAGE of ALL rainDensity amounts
       and a MAXIMUM value of all the precip types. This index will have the
       same date/time naming convention as a stats file and will reprsent what
       the entire contents of the radar cuts directory looks like when the
       'snapshot' is taken.
       
    latestRadarImage will look like this (for example):
        '/{path}/Config.1.Core1.0.Local_LocalDoppler.0.1171278600.1171290300.data.stats'
    """
    global glob
    globName = rootName + '.*.data.stats'
    statsList = glob.glob(globName)
    loopRainDensity = 0
    maxPrecipType = 0
    totalRainDensity = 0
    rainDensityCount = len(statsList)
    for statsFile in statsList:
        nsStats = {}
        try:
            execfile(statsFile, nsStats, nsStats)
        except:
            pass

        if nsStats.has_key('rainDensity'):
            rainDensity = nsStats['rainDensity']
            totalRainDensity += rainDensity
        else:
            twccommon.Log.warning("Missing 'rainDensity' in %s. Assuming a value of 5." % (statsFile,))
            totalRainDensity += 5
        if nsStats.has_key('precipType'):
            precipType = nsStats['precipType']
            if precipType > maxPrecipType:
                maxPrecipType = precipType
        else:
            twccommon.Log.warning("Missing 'precipType' in %s. Assuming a value of 3." % (statsFile,))
            maxPrecipType = 3

    loopRainDensity = round(float(totalRainDensity) / float(rainDensityCount))
    indexFile = '%s.%s.data.index' % (rootName, validTimeString)
    print('generating radar stats INDEX file: %s' % (indexFile,))
    f = open(indexFile, 'w+')
    f.write('# Radar Index File\n')
    f.write('loopRainDensity = %d   # (values > 5 are significant)\n' % (loopRainDensity,))
    f.write('maxPrecipType = %d     # (0=none,1=rain,2=mixed,3=snow)\n' % (maxPrecipType,))
    f.close()


def process(ftype, loc, iname, smooth):
    splitName = os.path.splitext(os.path.basename(iname))
    if splitName[1] == '.gz':
        os.system('gzip -d -f %s' % (iname,))
        fname = os.path.join(os.path.split(iname)[0], splitName[0])
        bname = os.path.splitext(os.path.basename(splitName[0]))[0]
    else:
        fname = iname
        print(fname)
        bname = splitName[0]
    rc = 0
    key = 'Config.%s.interestlist.%s.%s.cuts' % (1, ftype, loc)
    il = dsmarshal_get(key)
    print(key, il)
    for prod in il:
        mapDataKey = prod + '.MapData'
        attribs = dsmarshal_get(mapDataKey)
        print(prod, mapDataKey, attribs)
        rootName = '%s/%s/%s.cuts/%s' % (_config.imageRoot, ftype, loc, prod)
        dataName = rootName + '.%s.data.tif' % (bname,)
        tempName = rootName + '.%s.TEMP.tif' % (bname,)
        smoothName = rootName + '.%s.SMOOTH.tif' % (bname,)
        finalName = rootName + '.%s.tif' % (bname,)
        x = int(attribs.datacutCoordinate[0])
        y = int(attribs.datacutCoordinate[1])
        w = int(attribs.datacutSize[0])
        h = int(attribs.datacutSize[1])
        fw = int(attribs.dataFinalSize[0])
        fh = int(attribs.dataFinalSize[1])
        offsetX = int(attribs.dataOffset[0])
        offsetY = int(attribs.dataOffset[1])
        basemapW = int(attribs.mapFinalSize[0])
        basemapH = int(attribs.mapFinalSize[1])
        limitSize = 0
        if basemapW > 512:
            fw = int(fw * 512 / basemapW)
            fh = int(fh * 512 / basemapH)
            offsetX = int(offsetX * 512 / basemapW)
            offsetY = int(offsetY * 512 / basemapH)
            limitSize = 1
        print("I need to talk to you about basemapW:", basemapW)
        miles = int(int(attribs.mapMilesSize[0]) * (720 / basemapW))
        TWCPERSDIR = '/media/usr/twc/domestic'
        configFile = TWCPERSDIR + '/conf/imagecut.py'
        print("Check 1")
        smoothingApplication = '/usr/twc/smooth/bin/imageSmooth'
        version = dsmarshal_get('Config.1.version.twc_imagesmooth')
        print("Check 2", version)
        if version == None:
            print('Could not determine smoothing application version!')
        else:
            print('Smoothing with imageSmooth v%s' % (version,))
        if _config.radarImageScalingMethod == 'fixedPalette':
            scalingMethod = _config.radarImageScalingMethod
        elif _config.radarImageScalingMethod == 'colorAverage':
            scalingMethod = _config.radarImageScalingMethod
        else:
            err = 'Radar Scaling Method Unrecognized! Failed to cut for %s.' % dataName
            print(err)
            raise RuntimeError, err
        cmd = NICE_VALUE
        cmd += _config.imageCutTool
        print("Check 3")
        if limitSize:
            cmd += ' -i %s -o %s -l%d,%d -w%d -h%d -p%d,%d -S%d,%d                 -m%s -a0,0,0:20,20,20 -r -c %s -f%d,%d' % (fname, dataName, x, y, w, h, offsetX, offsetY, fw, fh, scalingMethod, configFile, 512, 512)
        else:
            cmd += ' -i %s -o %s -l%d,%d -w%d -h%d -p%d,%d -S%d,%d                 -m%s -a0,0,0:20,20,20 -r -c %s -f%d,%d' % (fname, dataName, x, y, w, h, offsetX, offsetY, fw, fh, scalingMethod, configFile, basemapW, basemapH)
        print('Cutting %s' % cmd)
        rc = os.system(cmd)
        if rc != 0:
            err = 'Image failed to cut for %s.' % dataName
            print(err)
            raise RuntimeError, err
        if _config.enableSmoothing and smooth == 1:
            if os.path.exists(smoothingApplication):
                cmd = NICE_VALUE
                print("Ok check 4")
                cmd += smoothingApplication
                cmd += genSmoothingCommandLine(dataName, smoothName, miles)
                print('Smoothing %s' % cmd)
                rc = os.system(cmd)
                if rc != 0:
                    err = 'Image failed to smooth for %s.' % dataName
                    print(err)
                    raise RuntimeError, err
                cmd = 'mv %s %s' % (smoothName, dataName)
                print('Moving %s' % cmd)
                print(cmd)
                rc = os.system(cmd)
                if rc != 0:
                    err = 'Image failed to rename from %s to %s.' % (smoothName, dataName)
                    print(err)
                    raise RuntimeError, err
            else:
                err = 'Application [%s] not found.' % smoothingApplication
                print(err)
                raise RuntimeError, err
        else:
            twccommon.Log.warning('Image smoothing NOT enabled.')
        cmd = NICE_VALUE
        cmd += _config.imageCutTool
        cmd += ' -i %s -o %s -a0,0,0' % (dataName, tempName)
        print('Adjusting %s' % cmd)
        rc = os.system(cmd)
        if rc != 0:
            err = 'Image failed to adjust for %s.' % finalName
            print(err)
            raise RuntimeError, err
        os.unlink(dataName)
        print("Check 5")
        os.rename(tempName, finalName)
        buildIndexFile(rootName, bname)

    return


NICE_VALUE = ''

CACHE_FILE = "cache.stratos"

def load_cache():
    processed = {}
    try:
        f = open(CACHE_FILE, "r")
        for line in f:
            line = line.strip()
            if line:
                processed[line] = 1
        f.close()
    except:
        pass
    return processed

def save_to_cache(path):
    try:
        f = open(CACHE_FILE, "a")
        f.write(path + "\n")
        f.close()
    except:
        print "Warning: Could not write to cache for", path

def main():
    print("Thanks for using i1RadarSlicer by Stratosphere Group.")
    print("This piece of software is brought to you by Daisy and Susie.")
    print("github/dalk21, github/hexad3c1mal")
    print("Version 1.0 - 10/19/2025")
    base_dir = "/media/usr/twc/domestic/data/volatile/images/"
    expected_dirs = ["radar/us", "radar/ak", "radar/hi", "radarSatellite/us", "snowfallQpfForecast/us"]

    processed = load_cache()

    for sub in expected_dirs:
        path = os.path.join(base_dir, sub)
        if not os.path.isdir(path):
            continue

        parts = sub.split("/")
        if len(parts) != 2:
            continue

        ftpye = parts[0]
        loc = parts[1]

        for fname in os.listdir(path):
            full_path = os.path.join(path, fname)

            # Skip if not a file or already processed
            if not os.path.isfile(full_path):
                continue
            if processed.has_key(full_path):
                continue
            smoothing = 0
            if sub.find("radar") != -1:
                smoothing = 1
            if sub.find("radarSatellite") != -1:
                smoothing = 1
            try:
                process(ftpye, loc, full_path, smoothing)
            except:
                print("Thats okay")
            save_to_cache(full_path)

if __name__ == "__main__":
    main()