#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on 29/12/21
@author: Benjamin Beauchesne
"""

import numpy as np
import sys
import os
from scipy.optimize import minimize
import argparse


def minimize_circle(X,data_mult,penalty,centre):

    """
    This function return the area of the circle to be minimized
    """

    area=np.pi*X**2
    for k in range(len(data_mult)):
        r=((data_mult[k,1]-centre[0])**2+(data_mult[k,2]-centre[1])**2)**0.5
        if r>X:
            area+=penalty
    return area
            



def get_centre_max_size(multfile,Ref):

    """
    Define a minimal circle that enclosed all the constraint as detailed in Beauchesne et al. 2021

    """

    data_mult=np.loadtxt(multfile)
    tmp=open(multfile,'r')
    header=(tmp.read()).split('\n')[0]
    header=header.split()
    tmp.close()
    if header[1]=='0':
        
        ref_mult=[float(header[2]),float(header[3])]
        
    if header[1]=='3':
        ref_mult=[float(header[2]),float(header[3])]
    # to relative ref to degree
        for k in range(len(data_mult)):
            data_mult[k,1],data_mult[k,2]=-data_mult[k,1]/np.cos(ref_mult[1]*np.pi/180)/3600+ref_mult[0],data_mult[k,2]/3600+ref_mult[1]
    # to degree to relative of the model
    for k in range(len(data_mult)):
        data_mult[k,1],data_mult[k,2]=-(data_mult[k,1]-ref_mult[0])*np.cos(ref_mult[1]*np.pi/180)*3600,(data_mult[k,2]-ref_mult[1])*3600
    centre=[np.mean(data_mult[:,1]),np.mean(data_mult[:,2])]
    sol=minimize(minimize_circle,[2*np.max((data_mult[:,1]**2+data_mult[:,2]**2)**0.5)],args=(data_mult,100000,centre))
    
    print("\n\n##################################################\n\n")
    print("You can check that the area defined by the patch of \nB-spline functions is correct according to your set \nof multiple images with the ds9 region area_Bspline.cat\n")
    print("\n\n##################################################\n\n")
    mul_verification=open("area_Bspline.cat",'w')
    mul_verification.write("#REFERENCE 3 %0.7f %0.7f\n"%(Ref[0],Ref[1]))
    mul_verification.write("1. %0.7f %0.7f %0.7f %0.7f 0 1.0 25.0"%(centre[0],centre[1],sol.x,sol.x))
    mul_verification.close()
    return sol.x[0],centre[0],centre[1]    


def print_potential(moving,lim_min,lim_max,centre,zl,kappa):
    """
    Print the limit and potential of a B-spline perturbation according to 
    Beauchesne et al. 2021
    """

    print("potentiel pert")
    print("\tprofil       814")
    print("\tx_centre     "+str(centre[0]))
    print("\ty_centre     "+str(centre[1]))
    print("\tangle_pos       0.0")
    print("\tz_lens     "+str(zl))
    print("\tdegx    5")
    print("\tdegy    5")
    print("\tn_coeff  "+str(int(moving)))
    print("\tsize_lattice    "+str(lim_min))
    print("\tfile_coeff coeff.txt")
    print("\tend")
    print("limit pert")
    print("\tx_centre     1 "+str(centre[0]-4)+" "+str(centre[0]+4)+" 0.100")
    print("\ty_centre     1 "+str(centre[1]-4)+" "+str(centre[1]+4)+" 0.100")
    print("\tangle_pos     1 -90.0 90.0 0.100")
    print("\tsize_lattice    1 "+str(lim_min)+" "+str(lim_max)+" 0.1")
    print("\tBs_coeff        3 0.0 "+str(kappa*lim_min**2/(4*2.7))+" 0.1")
    print("\tend")
   
    coeff_line=""
    for k in range(int(moving)**2):
        coeff_line+="0.0 "
    coeff_line=coeff_line[:-1]
    coeff_file=open("coeff.txt","w")
    coeff_file.write(coeff_line)
    coeff_file.close()
    return None


def defining_argument_for_parser(parser):

    """
    Argument definition of the command line tool

    """

    parser.add_argument("-MIF","--MultipleImageFile", help="Catalogue of multiple images in Lenstool format, with REFERENCE 0 or 3",
                    type=str,required=True)
    parser.add_argument("-zl", help="Redshift of the cluster",
                    type=float,required=True)

    parser.add_argument("-kappa", help="Kappa maximum value defined in equ. 16 of Beauchesne et al. 2021 (maximum of the second derivative)",
                    type=float,required=False,default=1.75)

    parser.add_argument("-Ref_RA", help="Right Ascencion of the reference point of the cluster model",
                    type=float,required=True)

    parser.add_argument("-Ref_DEC", help="Declination of the reference point of the cluster model",
                    type=float,required=True)

    parser.add_argument("-n","--n_coeff", help="Number of basis functions use - if n_coeff == 5 there is 5x5 basis functions",
                    type=float,required=True)


    args = parser.parse_args()

    mulfile=args.MultipleImageFile
    zl=args.zl
    kappa=args.kappa

    Ref=[args.Ref_RA,args.Ref_DEC]

    n_coeff=args.n_coeff

    return mulfile,zl,kappa,Ref,n_coeff


    



if __name__ == '__main__':

    parser = argparse.ArgumentParser()
    mulfile,zl,kappa,Ref,n_coeff=defining_argument_for_parser(parser)
    
    limandcentre=get_centre_max_size(mulfile,Ref)
    centre=[limandcentre[1],limandcentre[2]]
    
    patch_min=2*limandcentre[0] # radius to diameter
    
    patch_max=patch_min*1.2
    
    
    lim_min=patch_min/(n_coeff+1)
    lim_max=patch_max/(n_coeff+1)

    print_potential(n_coeff,lim_min,lim_max,centre,zl,kappa)
     
   
    
