#!/bin/sh

set -e

merge=1

file="$1"
if [ -z "$file" ]; then
  file="deps"
fi

dot="${file}.dot"
svg="${file}.svg"

norm()
{
    echo $1 | tr / _
}

colour()
{
    case $1 in
        Ice) col=lightblue;;
        IceUtil) col=blue;;
        Glacier2) col=navy;;
        stdlib) col=green;;
        omero) col=red;;
        omero/model) col=yellowgreen;;
        omero/api) col=plum;;
        omero/cmd) col=orange;;
        omero/util) col=turquoise;;
        *) col=black;;
    esac
    echo $col
}

group()
{
    unit=$1
    case "${1%/*}" in
        omero/api|omero/cmd|omero/model|omero/util|Ice|IceUtil|Glacier2)
            unit="${unit%/*}";;
        typeinfo|map|stdexcept|iosfwd|sstream|ostream|iostream|exception|vector|algorithm|string)
            unit="stdlib";;
        
    esac
    echo "$unit"
}

cat <<EOF > "$dot"
strict digraph G {
  graph [compound=true];
EOF

if [ "$merge" = "1" ]; then
    cat <<EOF >> "$dot"
  $(norm Ice) [label="Ice",color=$(colour Ice)];
  $(norm IceUtil) [label="IceUtil",color=$(colour IceUtil)];
  $(norm Glacier2) [label="Glacier2",color=$(colour Glacier2)];
  $(norm stdlib) [label="stdlib",color=$(colour stdlib)];
EOF
else
    cat <<EOF >> "$dot"
  subgraph cluster_$(norm Ice) {
    label = "Ice";
    style = solid;
    node [shape=box,color=lightblue];

    $(norm Ice/BasicStream) [label="BasicStream"];
    $(norm Ice/BuiltinSequences) [label="BuiltinSequences"];
    $(norm Ice/Current) [label="Current"];
    $(norm Ice/Direct) [label="Direct"];
    $(norm Ice/Exception) [label="Exception"];
    $(norm Ice/FactoryTableInit) [label="FactoryTableInit"];
    $(norm Ice/IncomingAsync) [label="IncomingAsync"];
    $(norm Ice/Incoming) [label="Incoming"];
    $(norm Ice/LocalException) [label="LocalException"];
    $(norm Ice/LocalObject) [label="LocalObject"];
    $(norm Ice/ObjectFactory) [label="ObjectFactory"];
    $(norm Ice/ObjectF) [label="ObjectF"];
    $(norm Ice/Object) [label="Object"];
    $(norm Ice/OutgoingAsync) [label="OutgoingAsync"];
    $(norm Ice/Outgoing) [label="Outgoing"];
    $(norm Ice/ProxyF) [label="ProxyF"];
    $(norm Ice/Proxy) [label="Proxy"];
    $(norm Ice/SlicedDataF) [label="SlicedDataF"];
    $(norm Ice/SlicedData) [label="SlicedData"];
    $(norm Ice/StreamF) [label="StreamF"];
    $(norm Ice/StreamHelpers) [label="StreamHelpers"];
    $(norm Ice/UndefSysMacros) [label="UndefSysMacros"];
  }
  subgraph cluster_$(norm IceUtil) {
    label ="IceUtil";
    style = solid;
    node [shape=box,color=lightblue];

    $(norm IceUtil/Config) [label="Config"];
    $(norm IceUtil/Iterator) [label="Iterator"];
    $(norm IceUtil/Optional) [label="Optional"];
    $(norm IceUtil/ScopedArray) [label="ScopedArray"];
  }
  subgraph cluster_$(norm Glacier2) {
    label ="Glacier2";
    style = solid;
    node [shape=box,color=lightblue];

    $(norm Glacier2/Session) [label="Session"];
  }
  subgraph cluster_$(norm stdlib) {
    label = "stdlib";
    style = solid;
    node [shape=box,color=$(colour stdlib)];

    $(norm typeinfo) [label="typeinfo"];
    $(norm map) [label="map"];
    $(norm stdexcept) [label="stdexcept"];
    $(norm iosfwd) [label="iosfwd"];
    $(norm sstream) [label="sstream"];
    $(norm ostream) [label="ostream"];
    $(norm iostream) [label="iostream"];
    $(norm exception) [label="exception"];
    $(norm vector) [label="vector"];
    $(norm algorithm) [label="algorithm"];
    $(norm string) [label="string"];
  }
EOF
fi

for component in omero omero/model omero/cmd omero/api omero/util; do
    echo "Processing component: $component"

    if [ "$component" != "omero" -a "$merge" = "1" ]; then
        cat <<EOF >> "$dot"
  $(norm $component) [label="$component",color=$(colour $component)];
EOF
    else
        cat <<EOF >> "$dot"
  subgraph cluster_$(norm $component) {
    label ="$component";
    style = solid;
    colour = $(colour $component);
    node [shape=box,color=$(colour $component)];

EOF

        sources=$( (find "$component" -maxdepth 1 -name "*.h"; find "$component" -maxdepth 1 -name "*.cpp") | sort)
        units=$(echo "$sources" | sed -e "s;\.h\$;;" -e "s;\.cpp\$;;" | uniq)
        echo "$units"

        for unit in $units; do
            echo "  Processing unit: $unit"
            name=${unit#*/}
            name=${name#*/}
            cat <<EOF >> "$dot"
    $(norm $unit) [label="$name"];
EOF
        done
        if [ component != "omero" ]; then
            cat <<EOF >> "$dot"
  }
EOF
        fi
    fi
done

# Process deps
for component in omero omero/model omero/cmd omero/api omero/util; do
    sources=$( (find "$component" -maxdepth 1 -name "*.h"; find "$component" -maxdepth 1 -name "*.cpp") | sort)

    for source in $sources; do
        echo -n "  Processing source: $source"
        unit=$(echo "$source" | sed -e "s;\.h\$;;" -e "s;\.cpp\$;;")
        name=${unit#*/}
        name=${name#*/}
        deps=$(grep "#include" "$source" | sed -e "s;#include.*<\(.*\)>.*;\1;")
        for dep in $deps; do
            dep=$(echo "$dep" | sed -e "s;\.h\$;;" -e "s;\.cpp\$;;")
            echo -n "."
            # Drop self-references
            if [ "$(norm $unit)" = "$(norm $dep)" ]; then continue; fi
            # Don't generate inter-module deps except for the omero component
#            if [ "${unit%/*}" != "$component" -o "$component" = "omero" ]; then
                if [ "$merge" = "1" ]; then
                    unit=$(group "$unit")
                    dep=$(group "$dep")
                fi
                cat <<EOF >> "$dot"
      $(norm $unit) -> $(norm $dep) [color=$(colour $dep)];
EOF
#            fi
        done
        echo "done."
    done
done

cat <<EOF >> "$dot"
}
EOF

ccomps -Cx "$dot" | dot | gvpack -array_1 | neato -n2 -Tsvg > "$svg"
egrep -v -- "->.*(Ice|Glacier|stdlib)" "$dot" | ccomps -C | dot | gvpack -array_1 | neato -n2 -Tsvg > "noice-$svg"
