#! /usr/bin/env python

#*****************************************************#
# This file is part of GRIDOPT.                       #
#                                                     #
# Copyright (c) 2015, Tomas Tinoco De Rubira.         #
#                                                     #
# GRIDOPT is released under the BSD 2-clause license. #
#*****************************************************#

from __future__ import print_function
import pstats
import argparse
import cProfile
import pfnet
import gridopt

methods = ['ACOPF','ACPF','DCOPF','DCPF']

def create_parser():
    
    # Construct parser
    parser = argparse.ArgumentParser(description='Power flow optimization package.')
    
    # Case
    parser.add_argument('case',type=str,
                        help='filename of power flow case to solve.')

    # Method
    parser.add_argument('method',choices=methods,metavar='method',
                        help='PF or OPF method { %(choices)s }.')
    
    # Params
    class ParamAction(argparse.Action):
        def __call__(self,parser,namespace,values,option_string=None):
            for value in values:
                if '=' not in value:
                    raise argparse.ArgumentTypeError("invalid parameter name-value pair")
                n,v = value.split('=')
                params = getattr(namespace,self.dest)
                setattr(namespace,self.dest,params+[(n,v)])
    parser.add_argument('--params',action=ParamAction,dest='params',nargs='*',default=[],
                        help='parameter name-value pairs.')

    # Profile
    parser.add_argument('--profile',action='store_true',default=False,
                        help='flag for profiling execution.')

    # FlatStart
    parser.add_argument('--flatstart',action='store_true',default=False,
                        help='flag for flat starting point.')

    return parser

def main():

    parser = create_parser()
    args = parser.parse_args()

    try:
        
        # Network
        net = pfnet.Parser(args.case).parse(args.case)
        net.show_components()
        
        if args.flatstart:

            # Flat start
            for bus in net.buses:
                bus.v_mag = 1
                bus.v_ang = 0
        
        # Method
        method = gridopt.power_flow.new_method(args.method)
            
        # Parameters
        method.set_parameters(strparams=dict(args.params))
            
        if args.profile:

            # Profile
            cProfile.runctx('method.solve(net)',globals(),locals(),'.prof')
            pstats.Stats('.prof').strip_dirs().sort_stats('cumulative').print_stats(20)
        else:

            # Solve
            try:
                method.solve(net)
                print(method.results['solver status'])
            except gridopt.power_flow.PFmethodError as e:
                print(e)
            
            # Update
            method.update_network(net)
                
            # Show network props
            net.show_properties()

    finally:
        pass
    
# Main function            
if __name__ == "__main__":
    main()
