#!/usr/bin/env python3
#
# Generate a graph and dump in standard output.
# Copyright (c) 2019-2023, Hiroyuki Ohsaki.
# All rights reserved.
#

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.

# This program is contributed by Hal.

import os
import random
import sys

home_dir = os.getenv('HOME')
sys.path.insert(1, f'{home_dir}/src/graph-tools')

from perlcompat import die, getopts
import graph_tools

def usage():
    prog = os.path.basename(sys.argv[0])
    types = '/'.join(graph_tools.CREATE_TYPES)
    export_fmts = '/'.join(graph_tools.EXPORT_FORMATS)
    die(f"""\
usage: {prog} [-du] [-s seed] [-t type] [-s seed] [-o format] params...
  -d         generate directed graph
  -u         generate undirected graph (default)
  -t type    specify graph type ({types})
             parameters (defaults):
                 random/random_sparse: [N [E [no_multiedge]]] (N=20, E=10)
                 erdos_renyi/er: [N [p]] (N=10, p=0.5)
                 barabasi/ba: [N [m [m0]]] (N=10, m=2, m0=2)
                 barandom: [N [E [m0]]] (N=10, E=10, m0=2)
                 ring: [N [step]] (N=10, step=1)
                 tree: [N] (N=10)
	         btree: [N] (N=10)
	         treeba: [N [alpha]] (N=10, alpha=1)
  	         general_ba: [N [m [gamma [m0]]]] (N=10, m=2, gamma=3, m0=2)
	         latent: [N [E [error_ratio [confer [dist [alpha]]]]]]
                     (N=10, E=20, error_ratio=0, confer=linear, dist=normal, alpha=10)
                     confer: abs/binary/linear/sigmoid
                     dist: uniform/normal/exponential
	         lattice: [dim [n [is_torus]]] (dim=2, n=5, is_torus=False)
	         voronoi: [npoints [width [height]]] (npoints=10, width=1, height=1)
                 degree_bounded/db: [N [E]] (N=10, E=20)
                 configuration [degree_seq] (degree_seq=6,5,4,3,3,3,2,2,1,1)
                 regular: [N [k]] (N=10, k=3)
                 li_maini: [T [M [m0 [m [alpha [n]]]]]] (T=200, M=4, m0=4, m=1, alpha=.1, n=1)
  -s seed    specify random number seed
  -o format  output graph format ({export_fmts})
""")

def validate_params(alist):
    params = []
    for param in alist:
        try:
            cls = type(eval(param))
            if cls == int:
                param = int(param)
            elif cls == float:
                param = float(param)
            elif cls == bool:
                param = True if param == 'True' else False
            else:
                param = map(int, param.split(','))
                param = list(param)
        except:
            pass
        params.append(param)
    return params

def main():
    opt = getopts('dut:s:o:') or usage()
    directed = False
    if opt.d:
        directed = True
    atype = opt.t if opt.t else 'random'
    seed = int(opt.s) if opt.s else None
    out_format = opt.o if opt.o else 'dot'

    if seed:
        random.seed(seed)
    g = graph_tools.Graph(directed)
    g = g.create_graph(atype, *validate_params(sys.argv[1:]))
    print(g.export_graph(out_format))

if __name__ == "__main__":
    main()
