function fname_out = savecase(fname, varargin)
%SAVECASE  Saves a MATPOWER case file, given a filename and the data matrices.
%
%   savecase(fname, casestruct)
%   savecase(fname, comment, casestruct)
%   savecase(fname, casestruct, version)
%   savecase(fname, comment, casestruct, version)
%   savecase(fname, baseMVA, bus, gen, branch)
%   savecase(fname, comment, baseMVA, bus, gen, branch)
%   savecase(fname, baseMVA, bus, gen, branch, areas, gencost)
%   savecase(fname, comment, baseMVA, bus, gen, branch, areas, gencost)
%   fname = savecase(fname, comment, baseMVA, bus, gen, branch, areas, gencost)
%
%   Writes a MATPOWER case file, given a filename and data struct or list of
%   data matrices. The fname parameter is the name of the file to be created or
%   overwritten. If fname ends with '.mat' it saves the case as a MAT-file
%   otherwise it saves it as an M-file. Optionally returns the filename,
%   with extension added if necessary. The optional 'comment' argument is
%   either string (single line comment) or a cell array of strings which
%   are inserted as comments. When using a MATPOWER case struct, if the
%   optional 'version' argument is '1' it will modify the data matrices to
%   version 1 format before saving.

%   MATPOWER
%   $Id: savecase.m,v 1.17 2006/03/14 21:38:35 ray Exp $
%   by Carlos E. Murillo-Sanchez, PSERC Cornell & Universidad Autonoma de Manizales
%   and Ray Zimmerman, PSERC Cornell
%   Copyright (c) 1996-2006 by Power System Engineering Research Center (PSERC)
%   See http://www.pserc.cornell.edu/matpower/ for more info.

%% define named indices into bus, gen, branch matrices
[PQ, PV, REF, NONE, BUS_I, BUS_TYPE, PD, QD, GS, BS, BUS_AREA, VM, ...
    VA, BASE_KV, ZONE, VMAX, VMIN, LAM_P, LAM_Q, MU_VMAX, MU_VMIN] = idx_bus;
[GEN_BUS, PG, QG, QMAX, QMIN, VG, MBASE, GEN_STATUS, PMAX, PMIN, ...
    MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN, PC1, PC2, QC1MIN, QC1MAX, ...
    QC2MIN, QC2MAX, RAMP_AGC, RAMP_10, RAMP_30, RAMP_Q, APF] = idx_gen;
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, ...
    TAP, SHIFT, BR_STATUS, PF, QF, PT, QT, MU_SF, MU_ST, ...
    ANGMIN, ANGMAX, MU_ANGMIN, MU_ANGMAX] = idx_brch;
[AREA_I, PRICE_REF_BUS] = idx_area;
[PW_LINEAR, POLYNOMIAL, MODEL, STARTUP, SHUTDOWN, NCOST, COST] = idx_cost;

%% default arguments
if isstr(varargin{1}) | iscell(varargin{1})
    comment = varargin{1};
    [args{1:(length(varargin)-1)}] = deal(varargin{2:end});
else
    comment = '';
    args = varargin;
end
mpc_ver = '2';              %% default MATPOWER case file version
if isstruct(args{1})        %% 1st real argument is a struct
    mpc = args{1};
    if length(args) > 1
        mpc.version = args{2};
        mpc_ver = mpc.version;
    end
    baseMVA = mpc.baseMVA;
    bus     = mpc.bus;
    gen     = mpc.gen;
    branch  = mpc.branch;
    if isfield(mpc, 'areas') & isfield(mpc, 'gencost')
        areas   = mpc.areas;
        gencost = mpc.gencost;
    end
else                        %% 1st real argument is NOT a struct
    baseMVA = args{1};
    bus     = args{2};
    gen     = args{3};
    branch  = args{4};
    mpc.baseMVA = baseMVA;
    mpc.bus     = bus;
    mpc.gen     = gen;
    mpc.branch  = branch;
    if length(args) > 5
        areas   = args{5};
        gencost = args{6};
        mpc.areas   = areas;
        mpc.gencost = gencost;
    end
end

%% modifications for version 1 format
if strcmp(mpc_ver, '1')
    %% remove extra columns of gen
    if size(gen, 2) >= MU_QMIN
        gen = gen(:, [1:PMIN, MU_PMAX:MU_QMIN]);
    else
        gen = gen(:, 1:PMIN);
    end
    %% use the version 1 values for column names
    shift = MU_PMAX - PMIN - 1;
    tmp = num2cell([MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN] - shift);
    [MU_PMAX, MU_PMIN, MU_QMAX, MU_QMIN] = deal(tmp{:});
    
    %% remove extra columns of branch
    if size(branch, 2) >= MU_ST
        branch = branch(:, [1:BR_STATUS, PF:MU_ST]);
    elseif size(branch, 2) >= QT
        branch = branch(:, [1:BR_STATUS, PF:QT]);
    else
        branch = branch(:, 1:BR_STATUS);
    end
    %% use the version 1 values for column names
    shift = PF - BR_STATUS - 1;
    tmp = num2cell([PF, QF, PT, QT, MU_SF, MU_ST] - shift);
    [PF, QF, PT, QT, MU_SF, MU_ST] = deal(tmp{:});
end

%% verify valid filename
l = length(fname);
rootname = [];
if l > 2
    if strcmp(fname(l-1:l), '.m')
        rootname = fname(1:l-2);
        extension = '.m';
    elseif l > 4
        if strcmp(fname(l-3:l), '.mat')
            rootname = fname(1:l-4);
            extension = '.mat';
        end
    end
end
if isempty(rootname)
    rootname = fname;
    extension = '.m';
    fname = [rootname, extension];
end

%% open and write the file
if strcmp(extension, '.mat')        %% MAT-file
    vflag = '';
    if str2num(version('-release')) > 13
        vflag = ' -V6';
    end
    if strcmp(mpc_ver, '1')
        if exist('gencost') == 1
            cmd = sprintf('save %s baseMVA bus gen branch areas gencost%s;', rootname, vflag); 
        else
            cmd = sprintf('save %s baseMVA bus gen branch%s;', rootname, vflag); 
        end
    else
        cmd = sprintf('save %s mpc%s;', rootname, vflag); 
    end
    eval(cmd);
else                                %% M-file
    %% open file
    [fd, msg] = fopen(fname, 'wt');     %% print it to an m-file
    if fd == -1
        error(['savecase: ', msg]);
    end
    
    %% function header, etc.
    if strcmp(mpc_ver, '1')
        if exist('gencost') == 1 & ~isempty(gencost)
            fprintf(fd, 'function [baseMVA, bus, gen, branch, areas, gencost] = %s\n', rootname);
        else
            fprintf(fd, 'function [baseMVA, bus, gen, branch] = %s\n', rootname);
        end
        prefix = '';
    else
        fprintf(fd, 'function mpc = %s\n', rootname);
        prefix = 'mpc.';
    end
    if length(comment) ~= 0
        if isstr(comment)
            fprintf(fd, '%% %s\n', comment);
        elseif iscell(comment)
            for k = 1:length(comment)
                fprintf(fd, '%% %s\n', comment{k});
            end
        end
    end
    fprintf(fd, '\n%%%% MATPOWER Case Format : Version %s\n', mpc_ver);    
    if ~strcmp(mpc_ver, '1')
        fprintf(fd, 'mpc.version = ''%s'';\n', mpc_ver);    
    end
    fprintf(fd, '\n%%%%-----  Power Flow Data  -----%%%%\n');
    fprintf(fd, '%%%% system MVA base\n');
    fprintf(fd, '%sbaseMVA = %g;\n\n', prefix, baseMVA);
    
    %% bus data
    ncols = size(bus, 2);
    fprintf(fd, '%%%% bus data\n');
    fprintf(fd, '%%\tbus_i\ttype\tPd\tQd\tGs\tBs\tarea\tVm\tVa\tbaseKV\tzone\tVmax\tVmin');
    if ncols >= MU_VMIN             %% opf SOLVED, save with lambda's & mu's
        fprintf(fd, '\tlam_P\tlam_Q\tmu_Vmax\tmu_Vmin');
    end
    fprintf(fd, '\n%sbus = [\n', prefix);
    if ncols < MU_VMIN              %% opf NOT SOLVED, save without lambda's & mu's
        fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%d\t%.8g\t%.8g\t%g\t%d\t%g\t%g;\n', bus(:, 1:VMIN).');
    else                            %% opf SOLVED, save with lambda's & mu's
        fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%d\t%.8g\t%.8g\t%g\t%d\t%g\t%g\t%.4f\t%.4f\t%.4f\t%.4f;\n', bus(:, 1:MU_VMIN).');
    end
    fprintf(fd, '];\n\n');
    
    %% generator data
    ncols = size(gen, 2);
    fprintf(fd, '%%%% generator data\n');
    fprintf(fd, '%%\tbus\tPg\tQg\tQmax\tQmin\tVg\tmBase\tstatus\tPmax\tPmin');
    if ~strcmp(mpc_ver, '1')
        fprintf(fd, '\tPc1\tPc2\tQc1min\tQc1max\tQc2min\tQc2max\tramp_agc\tramp_10\tramp_30\tramp_q\tapf');
    end
    if ncols >= MU_QMIN             %% opf SOLVED, save with mu's
        fprintf(fd, '\tmu_Pmax\tmu_Pmin\tmu_Qmax\tmu_Qmin');
    end
    fprintf(fd, '\n%sgen = [\n', prefix);
    if ncols < MU_QMIN              %% opf NOT SOLVED, save without mu's
        if strcmp(mpc_ver, '1')
            fprintf(fd, '\t%d\t%g\t%g\t%g\t%g\t%.8g\t%g\t%d\t%g\t%g;\n', gen(:, 1:PMIN).');
        else
            fprintf(fd, '\t%d\t%g\t%g\t%g\t%g\t%.8g\t%g\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g;\n', gen(:, 1:APF).');
        end
    else
        if strcmp(mpc_ver, '1')
            fprintf(fd, '\t%d\t%g\t%g\t%g\t%g\t%.8g\t%g\t%d\t%g\t%g\t%.4f\t%.4f\t%.4f\t%.4f;\n', gen(:, 1:MU_QMIN).');
        else
            fprintf(fd, '\t%d\t%g\t%g\t%g\t%g\t%.8g\t%g\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%.4f\t%.4f\t%.4f\t%.4f;\n', gen(:, 1:MU_QMIN).');
        end
    end
    fprintf(fd, '];\n\n');
    
    %% branch data
    ncols = size(branch, 2);
    fprintf(fd, '%%%% branch data\n');
    fprintf(fd, '%%\tfbus\ttbus\tr\tx\tb\trateA\trateB\trateC\tratio\tangle\tstatus');
    if ~strcmp(mpc_ver, '1')
        fprintf(fd, '\tangmin\tangmax');
    end
    if ncols >= QT                  %% power flow SOLVED, save with line flows
        fprintf(fd, '\tPf\tQf\tPt\tQt');
    end
    if ncols >= MU_ST               %% opf SOLVED, save with mu's
        fprintf(fd, '\tmu_Sf\tmu_St');
%% uncomment below if we ever implement something that computes these multipliers
%         if ~strcmp(mpc_ver, '1')
%             fprintf(fd, '\tmu_angmin\tmu_angmax');
%         end
    end
    fprintf(fd, '\n%sbranch = [\n', prefix);
    if ncols < QT                   %% power flow NOT SOLVED, save without line flows or mu's
        if strcmp(mpc_ver, '1')
            fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d;\n', branch(:, 1:BR_STATUS).');
        else
            fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\t%g\t%g;\n', branch(:, 1:ANGMAX).');
        end
    elseif ncols < MU_ST            %% power flow SOLVED, save with line flows but without mu's
        if strcmp(mpc_ver, '1')
            fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\t%.4f\t%.4f\t%.4f\t%.4f;\n', branch(:, 1:QT).');
        else
            fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\t%g\t%g\t%.4f\t%.4f\t%.4f\t%.4f;\n', branch(:, 1:QT).');
       end
    else                            %% opf SOLVED, save with lineflows & mu's
        if strcmp(mpc_ver, '1')
            fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f;\n', branch(:, 1:MU_ST).');
        else
            fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\t%g\t%g\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f;\n', branch(:, 1:MU_ST).');
%% uncomment below if we every implement something that computes these multipliers
%             fprintf(fd, '\t%d\t%d\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%g\t%d\t%g\t%g\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f\t%.4f;\n', branch(:, 1:MU_ANGMAX).');
        end
    end
    fprintf(fd, '];\n\n');
    
    %% OPF data
    if exist('gencost') == 1 & ~isempty(gencost)
        %% area data
        fprintf(fd, '%%%%-----  OPF Data  -----%%%%\n');
        fprintf(fd, '%%%% area data\n');
        fprintf(fd, '%sareas = [\n', prefix);
        if ~isempty(areas)
            fprintf(fd, '\t%d\t%d;\n', areas(:, 1:PRICE_REF_BUS).');
        end
        fprintf(fd, '];\n\n');
            
        %% generator cost data
        fprintf(fd, '%%%% generator cost data\n');
        fprintf(fd, '%%\t1\tstartup\tshutdown\tn\tx1\ty1\t...\txn\tyn\n');
        fprintf(fd, '%%\t2\tstartup\tshutdown\tn\tc(n-1)\t...\tc0\n');
        fprintf(fd, '%sgencost = [\n', prefix);
        if ~isempty(gencost)
            n = gencost(1, NCOST);
            if gencost(1, MODEL) == PW_LINEAR
                n = 2 * n;
            end
            template = '\t%d\t%g\t%g\t%d';
            for i = 1:n
                template = [template, '\t%g'];
            end
            template = [template, ';\n'];
            fprintf(fd, template, gencost.');
        end
        fprintf(fd, '];\n\n');
    end
    
    %% end
    fprintf(fd, 'return;\n');
    
    %% close file
    if fd ~= 1
        fclose(fd);
    end
end

if nargout > 0
    fname_out = fname;
end

return;
