/**
* Copyright (C) Zhang,Yuexiang (xfeep)
*
*/
package nginx.clojure;
import static nginx.clojure.MiniConstants.DEFAULT_ENCODING;
import static nginx.clojure.MiniConstants.HEADERS_NAMES;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_ARRAY_ELTS_OFFSET;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_ARRAY_NELTS_OFFSET;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_HEADERSO_HEADERS_OFFSET;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_PTR_SIZE;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_TEL_HASH_OFFSET;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_TEL_KEY_OFFSET;
import static nginx.clojure.MiniConstants.NGX_HTTP_CLOJURE_TEL_VALUE_OFFSET;
import static nginx.clojure.MiniConstants.NGX_OK;
import static nginx.clojure.NginxClojureRT.UNSAFE;
import static nginx.clojure.NginxClojureRT.fetchNGXInt;
import static nginx.clojure.NginxClojureRT.fetchNGXString;
import static nginx.clojure.NginxClojureRT.ngx_array_destory;
import static nginx.clojure.NginxClojureRT.ngx_array_init;
import static nginx.clojure.NginxClojureRT.ngx_array_push_n;
import static nginx.clojure.NginxClojureRT.ngx_http_clojure_mem_shadow_copy_ngx_str;
import static nginx.clojure.NginxClojureRT.pushNGXInt;
import static nginx.clojure.NginxClojureRT.pushNGXString;
import java.util.Arrays;
import java.util.List;
public class ArrayHeaderHolder extends AbstractHeaderHolder {
public ArrayHeaderHolder(String name, long offset, long headersOffset) {
super(name, offset, headersOffset);
}
@Override
public void push(long h, long pool, Object v) {
long haddr = h + offset;
if (haddr == 0){
throw new RuntimeException("invalid address for set header array value " + v);
}
clear(h);
List<String> seq = null;
if (v == null || v instanceof String) {
String val = (String) v;
seq = Arrays.asList(val);
}else if (v instanceof List) {
seq = (List) v;
}else if (v.getClass().isArray()){
seq = (List)Arrays.asList((Object[])v);
}
int c = seq.size();
if (c == 0) {
return;
}
long lp = UNSAFE.getAddress(haddr + NGX_HTTP_CLOJURE_ARRAY_ELTS_OFFSET);
if (lp != 0) {
ngx_array_destory(haddr);
}
long code = ngx_array_init(haddr, pool, c, NGX_HTTP_CLOJURE_PTR_SIZE);
if (code != NGX_OK) {
throw new RuntimeException("can not init ngx array for header, return code:" + code);
}
lp = ngx_array_push_n(haddr, c);
if (lp == 0) {
throw new RuntimeException("can not push ngx array for header");
}
long pname = HEADERS_NAMES.get(name);
for (String val : seq) {
if (val != null) {
long p = NginxClojureRT.ngx_list_push(h + NGX_HTTP_CLOJURE_HEADERSO_HEADERS_OFFSET);
if (p == 0) {
throw new RuntimeException("can not push ngx list for headers");
}
pushNGXInt(p + NGX_HTTP_CLOJURE_TEL_HASH_OFFSET, 1);
ngx_http_clojure_mem_shadow_copy_ngx_str(pname, p + NGX_HTTP_CLOJURE_TEL_KEY_OFFSET);
pushNGXString(p + NGX_HTTP_CLOJURE_TEL_VALUE_OFFSET, val, DEFAULT_ENCODING, pool);
UNSAFE.putAddress(lp, p);
lp += NGX_HTTP_CLOJURE_PTR_SIZE;
}
}
}
@Override
public void clear(long h) {
long haddr = h + offset;
if (haddr == 0){
throw new RuntimeException("invalid address for clear header array value ");
}
long lp = UNSAFE.getAddress(haddr + NGX_HTTP_CLOJURE_ARRAY_ELTS_OFFSET);
if (lp != 0) {
int c = fetchNGXInt(haddr+NGX_HTTP_CLOJURE_ARRAY_NELTS_OFFSET);
for (; c > 0; c--) {
pushNGXInt(UNSAFE.getAddress(lp) + NGX_HTTP_CLOJURE_TEL_HASH_OFFSET, 0);
lp += NGX_HTTP_CLOJURE_PTR_SIZE;
}
pushNGXInt(haddr+NGX_HTTP_CLOJURE_ARRAY_NELTS_OFFSET, 0);
UNSAFE.putAddress(haddr + NGX_HTTP_CLOJURE_ARRAY_ELTS_OFFSET, 0);
}
}
@Override
public Object fetch(long h) {
long haddr = h + offset;
if (haddr == 0){
throw new RuntimeException("invalid address for fetch header array ");
}
long lp = UNSAFE.getAddress(haddr + NGX_HTTP_CLOJURE_ARRAY_ELTS_OFFSET);
if (lp == 0) {
return null;
}
int c = fetchNGXInt(haddr+NGX_HTTP_CLOJURE_ARRAY_NELTS_OFFSET);
if (c == 0) {
return null;
}
long tp;
if (c == 1) {
tp = UNSAFE.getAddress(lp);
if (tp == 0) {
return null;
}
return fetchNGXString(tp+NGX_HTTP_CLOJURE_TEL_VALUE_OFFSET, DEFAULT_ENCODING);
}
String[] vals = new String[c];
for (int i = 0; i < c; i++) {
tp = UNSAFE.getAddress(lp);
if (tp == 0) {
return null;
}
vals[i] = fetchNGXString(tp+ NGX_HTTP_CLOJURE_TEL_VALUE_OFFSET, DEFAULT_ENCODING);
lp += NGX_HTTP_CLOJURE_PTR_SIZE;
}
return vals;
}
@Override
public boolean exists(long h) {
long haddr = h + offset;
if (haddr == 0){
throw new RuntimeException("invalid address for fetch header array ");
}
long lp = UNSAFE.getAddress(haddr + NGX_HTTP_CLOJURE_ARRAY_ELTS_OFFSET);
if (lp == 0) {
return false;
}
int c = fetchNGXInt(haddr+NGX_HTTP_CLOJURE_ARRAY_NELTS_OFFSET);
if (c == 0) {
return false;
}
return true;
}
}